012

阅读: 评论:0

012

012

数据源

JDBC数据源DriverManagerDataSource

主要参数如下:

  • jdbcDriver:jdbc驱动
  • url:数据库连接
  • username:用户名
  • password:密码

DBCP数据源BasicDataSource

该数据源依赖于 commons-dbcp.jar, commons-pool对象池机制的数据库连接池。BasicDataSource提供了close()方法关闭数据源,所以必须设定destroy-method=”close”属性, 以便Spring容器关闭时,数据源能够正常关闭。除以上必须的数据源属性外,还有一些常用的属性。

  • defaultAutoCommit:设置从数据源中返回的连接是否采用自动提交机制,默认值为 true
  • defaultReadOnly:设置数据源是否仅能执行只读操作, 默认值为 false
  • maxActive:最大连接数据库连接数,设置为0时,表示没有限制
  • maxIdle:最大等待连接中的数量,设置为0时,表示没有限制
  • maxWait:最大等待秒数,单位为毫秒, 超过时间会报出错误信息
  • validationQuery:用于验证连接是否成功的查询SQL语句,SQL语句必须至少要返回一行数据, 如你可以简单地设置为:“select count(*) from user”
  • removeAbandoned:是否自我中断,默认是 false
  • removeAbandonedTimeout:几秒后数据连接会自动断开,在removeAbandoned为true,提供该值
  • logAbandoned:是否记录中断事件, 默认为 false

C3P0数据源ComboPooledDataSource

C3P0是一个开放源代码的JDBC数据源实现项目,它在lib目录中与Hibernate一起发布,实现了JDBC3和JDBC2扩展规范说明的 Connection 和Statement 池。C3P0类包c3p0-0.9.0.4.jar。C3P0拥有比DBCP更丰富的配置属性,通过这些属性,可以对数据源进行各种有效的控制。

HikariCP

官网:.html
HikariCP代码非常轻量,并且速度非常的快。 HikariCP在 spring-boot-starter-jdbc 中已经被引入,意味着它是spring默认推荐的数据源。

HikariConfig配置

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/simpsons");
config.setUsername("bart");
config.setPassword("51mp50n");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");HikariDataSource ds = new HikariDataSource(config)

HikariDataSource直接配置

HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:mysql://localhost:3306/simpsons");
ds.setUsername("bart");
ds.setPassword("51mp50n");

使用配置文件

HikariConfig config = new HikariConfig("/some/path/hikari.properties");
HikariDataSource ds = new HikariDataSource(config);

使用java.util.Properties

Properties props = new Properties();
props.setProperty("dataSourceClassName", "org.postgresql.ds.PGSimpleDataSource");
props.setProperty("dataSource.user", "test");
props.setProperty("dataSource.password", "test");
props.setProperty("dataSource.databaseName", "mydb");
props.put("dataSource.logWriter", new PrintWriter(System.out));HikariConfig config = new HikariConfig(props);
HikariDataSource ds = new HikariDataSource(config);

HikariCP配置说明

必要的属性
属性说明默认值
dataSourceClassNameJDBC驱动程序提供的数据源类的名称。注意:不支持XA数据源。如果使用jdbcUrl配置,则不需配置此属性null
jdbcUrljdbc链接urlnull
username数据库用户名null
password数据库密码null
driverClassName数据库驱动null
常用属性
属性说明默认值
autoCommit控制从池返回的连接的默认自动提交行为true
connectionTimeout连接超时时间,超出此时间将抛出SQLException。支持最低250ms默认值:30000(30秒)
idleTimeout空闲连接存活的最长时间。只在minimumIdle < maximumPoolSize时有效。即当前连接数小于minimumIdle 时存活的连接不会失效。最小允许值为10000ms(10秒)。0表示不失效默认值:600000(10分钟)
maxLifetime连接的最大生存期。正在使用的连接不会失效。它也遵从idleTimeout 的设置默认值:1800000(30分钟)
connectionTestQuery用于检查连接是否有效的sql查询语句(例如:select 1 from dual)。适用于JDBC4以前的驱动程序。建议您先不要设置,如果你的驱动程序不是JDBC4,HikariCP会报错,否则会正常运行。
minimumIdle允许的空闲连接的最小数量默认值:与maximumPoolSize相同(注意:最好是小于最大值)
maximumPoolSize允许的连接数最大值(包括空闲连接+正在使用的连接)。当连接数到达该数量,则等待connectionTimeout毫秒,超出则抛出异常。默认值:10
poolName此属性表示连接池的用户定义名称,主要出现在日志和JMX管理控制台中,用于标识池和池配置。默认值:自动生成
不常用属性

还有很多不常用属性,请自行查询官网把。

Druid

Druid连接池是阿里巴巴开源的数据库连接池项目。Druid连接池为监控而生,内置强大的监控功能,监控特性不影响性能。功能强大,能防SQL注入,内置Loging能诊断Hack应用行为。
Github项目地址
文档 /%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98
下载 /
监控DEMO 120.26.192.168/druid/index.html

Druid对比HikariCP

HikariCP简洁,速度快,Druid功能强大,二者侧重点不同,如果你不需要过多的功能,只专注于提供连接池的话,推荐使用HikariCP。

友情提示:使用Druid如果不使用它的监控功能,请做如下配置

# 禁用druid监控,如果启用,请设置用户名密码(否则会有未授权的漏洞),默认是true
spring.datasource.abled=false

Spring的DAO抽象

  • JdbcDaoSupport:JDBC DAO抽象类。开发者需要为它设置数据源(DataSource),通过其子类,可以获得JdbcTemplate来访问数据库。
  • HibernateDaoSupport:Hibernate DAO抽象类。开发者需要配置Hibernate sessionFactory,通过其子类,可以获得HibernateTemplate来访问数据库。HibernateTemplate中有execute和executeFind两个方法接受一个HibernateCallback接口回调,在该接口中的doInHibernate方法中可以直接使用Session,以及其涉及到的HibernateAPI如Query对象等对象。
  • JdoDaoSupport:String为JDO提供的DAO抽象类,开发者需要为它配置PersistenceManagerFactory,通过其子类,可以获得JdoTemplate来访问数据库。

JdbcTemplate + HikariCP数据源示例

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns=".0.0"xmlns:xsi=""xsi:schemaLocation=".0.0 .0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId&ytest</groupId><artifactId>springboot</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><!-- spring-boot-starter-parent是一个特殊的启动器,他可以使我们在下面定义jar依赖时,不用提供版本标签 version --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.1</version></parent><dependencies><!-- 添加web依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- spring jdbc相关依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>6.0.6</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

可以看到与我们之前的依赖相比,就只多了spring-boot-starter-jdbc依赖和mysql的驱动依赖

Properties文件

jdbcUrl=jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
username=用户名
password=密码
driverClassName&#sql.cj.jdbc.Driver

中间汉字部分请自行替换

创建数据库表

我们使用mysql创建如下两张表,用于示例展示

表名:t_test,有3个字段。

表名:t_demo,有3个字段

配置HikariCP数据源

boot.dao;import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import t.annotation.Bean;
import t.annotation.ComponentScan;
import t.annotation.Configuration;
import io.Resource;import javax.sql.DataSource;
import java.io.IOException;@Configuration
@ComponentScan(&#boot.dao")
public class DaoConfig {@Value("classpath:dao.properties")private Resource configResource;@Beanpublic DataSource getDriverManagerDataSource() throws IOException {//-- 此处使用了Resource ,请查看Resource章节String propertiesPath = File().getAbsolutePath();HikariConfig hikariConfig = new HikariConfig(propertiesPath);HikariDataSource ds = new HikariDataSource(hikariConfig);return ds;}}

测试代码(先验证数据源)

boot.dao;import org.junit.Test;
import t.annotation.AnnotationConfigApplicationContext;import javax.sql.DataSource;public class Demo1 {@Testpublic void test(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();ister(DaoConfig.class);fresh();isterShutdownHook();DataSource dataSource = Bean(DataSource.class);System.out.println(dataSource);}}

建议在架构搭建的过程中进行分段验证,避免一次写完所有配置,再执行。否则如果出现错误或问题,你的架构代码半天也启动不起来。

注意&#isterShutdownHook();的作用,如果没有该语句,spring在程序执行完成(容器关闭时)不会回调关闭相应的资源(如:连接池的释放等)。所以isterShutdownHook();还是十分有必要的。

配置JdbcTemplate

在配置类中添加JdbcTemplate的配置

boot.dao;import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import t.annotation.Bean;
import t.annotation.ComponentScan;
import t.annotation.Configuration;
import io.Resource;
import org.JdbcTemplate;import javax.sql.DataSource;
import java.io.IOException;@Configuration
@ComponentScan(&#boot.dao")
public class DaoConfig {@Value("classpath:dao.properties")private Resource configResource;@Beanpublic DataSource getDriverManagerDataSource() throws IOException {String propertiesPath = File().getAbsolutePath();HikariConfig hikariConfig = new HikariConfig(propertiesPath);HikariDataSource ds = new HikariDataSource(hikariConfig);return ds;}/**** 因为JdbcTemplate一旦创建就是线程安全的,所以我们可以将它定义为一个单例的bean**/@Beanpublic JdbcTemplate getJdbcTemplate(DataSource dataSource){return new JdbcTemplate(dataSource);}}

JdbcTemplate用了ThreadLocal,使各线程能够保持各自独立的一个对象,其实就是一个变量副本,实现了线程安全。 JdbcTemplate类的实例是线程安全的实例。这一点非常重要,正因为如此,你可以配置一个简单的JdbcTemplate实例,并将这个“共享的”、“安全的”实例注入到不同的DAO类中去。 另外, JdbcTemplate 是有状态的,因为他所维护的DataSource 实例是有状态的,但是这种状态是无法变化的。 一旦JdbcTemplate被创建,他是一个线程安全的对象。 一个你需要创建多次JdbcTemplate实例的理由可能在于,你的应用需要访问多个不同的数据库,从而需要不同的DataSources来创建不同的JdbcTemplates实例。

编写dao类

TestDao和TestDaoImpl

boot.dao.dao;boot.dao.beans.TestBean;public interface TestDao {int insert(TestBean bean);int update(TestBean bean);TestBean getTestBeanById(int id);}
boot.dao.dao;boot.dao.beans.TestBean;
import org.JdbcTemplate;
import org.springframework.stereotype.Repository;import javax.annotation.Resource;@Repository
public class TestDaoImpl implements TestDao {@Resourceprivate JdbcTemplate jdbcTemplate;@Overridepublic int insert(TestBean bean) {return jdbcTemplate.update("insert into t_test(id,name,remark) values(?,?,?)",Id(),Name(),Remark());}@Overridepublic int update(TestBean bean) {return jdbcTemplate.update("update set t_test name = ?,remark=? where id = ?",Id(),Name(),Remark());}@Overridepublic TestBean getTestBeanById(int id) {return jdbcTemplate.queryForObject("select id,name,remark from t_test where id = "+id,TestBean.class);}
}

DemoDao和DemoDaoImpl

boot.dao.dao;boot.dao.beans.DemoBean;public interface DemoDao {int insert(DemoBean bean);int update(DemoBean bean);DemoBean getTestBeanById(int id);}
boot.dao.dao;boot.dao.beans.DemoBean;
boot.dao.beans.TestBean;
import org.JdbcTemplate;
import org.springframework.stereotype.Repository;import javax.annotation.Resource;@Repository
public class DemoDaoImpl implements DemoDao {@Resourceprivate JdbcTemplate jdbcTemplate;@Overridepublic int insert(DemoBean bean) {return jdbcTemplate.update("insert into t_demo(id,`key`,`value`) values(?,?,?)",Id(),Key(),Value());}@Overridepublic int update(DemoBean bean) {return jdbcTemplate.update("update set t_demo `key` = ?,`value`=? where id = ?",Id(),Key(),Value());}@Overridepublic DemoBean getTestBeanById(int id) {return jdbcTemplate.queryForObject("select id,`key`,`value` from t_demo where id = "+id, DemoBean.class);}
}

注:

  1. key、value是保留关键字,我们的sql字符串使用了反引号,如果不使用JdbcTemplate会报错。
  2. 我们看到两个Dao实现类都使用了 @Resource 注入了一个JdbcTemplate引用。其实我们可以定义一个BaseDao和BaseDaoImpl,在BaseDaoImpl中注入一次JdbcTemplate引用即可,其他的DaoImpl继承该BaseDaoImpl即可。

定义一个测试Service

boot.dao.service;boot.dao.beans.DemoBean;
boot.dao.beans.TestBean;public interface MyService {void insert(TestBean test, DemoBean demo);}
boot.dao.service;boot.dao.beans.DemoBean;
boot.dao.beans.TestBean;
boot.dao.dao.DemoDao;
boot.dao.dao.TestDao;
import org.springframework.stereotype.Service;import javax.annotation.Resource;@Service
public class MyServiceImpl implements MyService {@Resourceprivate TestDao test1Dao;@Resourceprivate DemoDao demoDao;@Overridepublic void insert(TestBean test, DemoBean demo) {test1Dao.insert(test);demoDao.insert(demo);}
}

我们此处只定义了一个insert方法,方法中同事insert了两个表,个一条数据。如要验证其他Dao方法,请自己补全把。

测试demo

boot.dao;boot.dao.beans.DemoBean;
boot.dao.beans.TestBean;
boot.dao.service.MyService;
import org.junit.Test;
import t.annotation.AnnotationConfigApplicationContext;import javax.sql.DataSource;public class Demo1 {@Testpublic void test(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();ister(DaoConfig.class);fresh();isterShutdownHook();DataSource dataSource = Bean(DataSource.class);System.out.println(dataSource);MyService service = Bean(MyService.class);TestBean bean = new TestBean();bean.setId(1);bean.setName("测试名称");bean.setRemark("测试备注");DemoBean demo = new DemoBean();demo.setId(1);demo.setKey("demokey");demo.setValue("demovalue");service.insert(bean,demo);}}

完整的代码结构

示例Service中,如果 test1Dao.insert(test); 之后demoDao.insert(demo);之前有其它业务逻辑代码,而且在这些逻辑代码中出现了异常,我们目前的代码会出现t_test表插入成功而t_demo表插入失败的问题。这显然是不符合业务逻辑的。我们将在下一章介绍此涉及到的事务问题。

上一篇:011-Spring AOP入门
下一篇:013-Spring事务管理

本文发布于:2024-02-01 16:13:50,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170677523237860.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23