概述
05如何配置单数据源
Spring Boot 的配置演示
- 引入对应数据库驱动–H2
- 引入JDBC依赖–spring-boot-starter-jdbc
- 获取DataSource Bean,打印信息
- 也可通过/acturator/beans 查看Bean
实例代码
@Slf4j //引入日志
implements CommandLineRunner // 实现顺序启动线程
// springboot 会默认注册一个H2 JDBC 在application中添加配置
management.endpoints.web.exposure.include=* // 可在Web浏览器中访问
直接配置所需的Bean
数据源相关
- DataSource(根据选择的连接池实现决定)
事务相关(可选)
- PlatformTransactionManager(DataSourceTransactionManager)
- TransactionTemplate
操作相关(可选)
- JDBCTemplate
Spring Boot 做了哪些配置
DataSourceAutoConfiguration
- 配置DataSource
DataSoureTransactionManagerAutoConfiguration
- 配置DataSourceTransactionManager
JdbcTemplateAutoConfigurtion
- 配置JdbcTemplate
符合条件才能配置
数据源相关配置
通用
- spring.datasource.url=jdbc:mysql//localhost/test
- spring.databsource.username=dbuser
- spring.databsource.password-dbpass
- spring.databsource.driver-class-name=com.mysql.jdbc.Driver(可选)
初始化内嵌数据库
- spring.datasource.initalization-mode=embedded|always|never
- spring.datasource.schema与spring.datasource.data确定初始化SQL文件
- spring.datasource.platform=hsqldb|h2|oracle|mysql|postgresql(与前者对应)
初始化数据量
-- 创建schema.sql文件,会默认执行此脚本
create table foo(id int identity,bar varchar(64))
-- 创建data.sql文件,会默认插入此脚本数据
insert into foo
application.properties 设置彩色打印日志
spring.output.ansi.enabled=always
06如何配置多数据源
配置多数据源的配置要分开
- 有多个DataSource时系统如何判断
- 对应的设施(事务、ORM等)如何选择DataSource
Spring Boot中的多数据源配置
手工配置两组DataSource及相关内容
与Spring Boot协同工作(二选一)
- 配置@Primary类型的Bean
- 排除Spring Boot的自动配置
DataSourceAutoConfiguration
DataSourceTransactionManagerAutoConfiguration
JdbcTemplateAutoConfiguration
Application.perproties配置文件
management.endpoints.web.exposure.include=*
spring.output.ansi.enabled=always
foo.datasource.url=jdbc:h2:men:foo
foo.datasource.username=sa
foo.datasource.password=
bar.datasource.url=jdbc:h2:men:bar
bar.datasource.username=sa
bar.datasource.password=
MultiDatasourceApplication 启动类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JdbcTemplateAutoConfiguration.class})
@Slf4j
public class MultiDatasourceApplication {
public static void main(String[] args) {
SpringApplication.run(MultiDatasourceApplication.class, args);
}
@Bean
@ConfigurationProperties("foo.datasource")
public DataSourceProperties fooDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
public DataSource fooDataSource() {
DataSourceProperties dataSourceProperties = fooDataSourceProperties();
log.info("foo datasource: {}", fooDataSourceProperties().getUrl());
return dataSourceProperties.initializeDataSourceBuilder().build();
}
@Bean
@Resource
public PlatformTransactionManager fooTxManager(DataSource fooDataSource) {
return new DataSourceTransactionManager(fooDataSource);
}
@Bean
@ConfigurationProperties("bar.datasource")
public DataSourceProperties barDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
public DataSource barDataSource() {
DataSourceProperties dataSourceProperties = barDataSourceProperties();
log.info("foo datasource: {}", barDataSourceProperties().getUrl());
return dataSourceProperties.initializeDataSourceBuilder().build();
}
@Bean
@Resource
public PlatformTransactionManager barTxManager(DataSource barDataSource) {
return new DataSourceTransactionManager(barDataSource);
}
}
07那些好用的连接池:HikariCP
HikariCP为什么快
- 字节码级别优化(很多方法通过JavaAssist)
- 大量小改进
- 用FastStatementList代替ArrayList
- 无锁集合ConncurrentBag
- 代理类的优化(比如,⽤ invokestatic 代替了 invokevirtual)
Spring Boot中的配置
spring Boot 2.x
- 默认使用HikariCp
- 配置spring.datasource.hikari.* 配置
Spring Boot 1.x
- 默认使用Tomcat连接池,需要移除tomcat-jdbc依赖
- spring.datasource.type=com.zaxxxer.hikari.HikariDataSource
常用HikariCP配置参数
- spring.datasource.hikari.maxmumPoolSize=10
- spring.datasource.hikari.minimumldle=10
- spring.datasource.hikari.idleTimeout=600000
- spring.datasource.hikari.connectionTimout=30000
- spring.datasource.hikari.maxLifrtime=1800000
其他配置详见HikariCP官网
- https://github.com/brettwooldridge/HikariCP
07那些好用的连接池:HikariCP
HikariCP为什么快
- 字节码级别优化(很多方法通过JavaAssist)
- 大量小改进
- 用FastStatementList代替ArrayList
- 无锁集合ConncurrentBag
- 代理类的优化(比如,⽤ invokestatic 代替了 invokevirtual)
Spring Boot中的配置
spring Boot 2.x
- 默认使用HikariCp
- 配置spring.datasource.hikari.* 配置
Spring Boot 1.x
- 默认使用Tomcat连接池,需要移除tomcat-jdbc依赖
- spring.datasource.type=com.zaxxxer.hikari.HikariDataSource
常用HikariCP配置参数
- spring.datasource.hikari.maxmumPoolSize=10
- spring.datasource.hikari.minimumldle=10
- spring.datasource.hikari.idleTimeout=600000
- spring.datasource.hikari.connectionTimout=30000
- spring.datasource.hikari.maxLifrtime=1800000
其他配置详见HikariCP官网
- https://github.com/brettwooldridge/HikariCP
08那些好⽤的连接池Alibaba Druid
“Durid连接池是阿里巴巴开源的数据库连接池项目。Druid连接池为监控而生,内置强大的监控功能,监控
特性不影响性能。功能强大,内置Logging能诊断Hack应用行为。” ——Alibaba Druid官方介绍
Durid
经过阿里巴巴大系统的考验,值得信赖
实用功能
- 详细的监控(非常全面)
- ExceptionSorter,针对主流数据库的返回码都有支持
- SQL防注入
- 内置加密配置
- 众多扩展点,方便进行定制
数据源配置
直接配置DruidDataSource
通过druid-spring-boot-starter
- spring.datasource.druid.*
spring.output.ansi.enabled=ALWAYS
spring.datasource.url=jdbc:h2:mem:foo
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.druid.inital-size=5
spring-datasource.druid.max-active=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.filters=conn,config,stat,slf4j
spring.datasource.druid.connection-properties=config.decrypt=true;config.decrypt.key=${pulic-key}
spring.datasource.druid.filter.config.enabled=true
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.test-on-return=true
spring.datasource.druid.test-while-idle=true
数据源配置
Filter 配置
- spring.datasource.druid.filters=stat,config,wall,log4j (全部使用默认值)
密码加密
- spring.datasource.password=<加密密码>
- spring.datasource.druid.filter.config.enabled=true
- spring.datasource.druid.connection-properties=config.decrypt=true;config.decrypt.key=
SQL防注入
- spring.datasource.druid.filter.wall.enabled=true
- spring.datasource.druid.filter.wall.db-type=h2
- spring.datasource.druid.filter.wall.config.delete-allow=false
- spring.datasource.druid.filger.wall.config.drop-table-allow=false
Druid Filter
- 用于定制连接池操作的各种环节
- 可以继承FilterEventAdapter
- 修改META-INF/druid-filter.properties 增加Filter配置
public class connectionLogFilterEventAdapter{
@Override
public void connection_connecBefore(FilterChain chain,Properties info){
log.info("BEFORE CONNECTION");
}
@Override
public void connection_connecAfter(ConnectionProxy connection){
log.info("AFTER connection!");
}
连接池选择时的考虑点
- 可靠性
- 性能
- 功能
- 可运维性
- 可扩展性
- 其他
通过Spring JDBC 访问数据库
Spring的JDBC操作类
spring-jdbc
- core、JdbcTemplate 等相关核心接口和类
- datasource,数据源相关的辅助类
- object,将基本的JDBC操作封装成对象
- support,错误码等其他辅助工具
常见的Bean 注解
通过注解定义Bean
- @Component
- @Repository
- @Service
- @Controller
- @RestController
简单的JDBC操作
JdbcTemplate
- query
- queryForObject
- queryForList
- update
- execute
SQL批处理
JdbcTemplate
- batchUpdate
- BatchPreparedStatementSetter
NamedParamerterJdbcTemplate
- batchUpdate
- SqlParameterSourceUtile.createBatch
Project Code
- 创建数据库,创建schema.sql文件
CREATE TABLE FOO (ID INT IDENTITY, BAR VARCHAR(64));
- 初始化数据库,插入数据
INSERT INTO FOO (BAR) VALUES ('aaa');
- 创建类实体
@Data
@Builder
public class Foo {
private Long id;
private String bar;
}
- 创建Dao层,数据操作层
@Slf4j
@Repository
public class FooDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private SimpleJdbcInsert simpleJdbcInsert;
public void insertData() {
// asList作用:初始化数组
Arrays.asList("b", "c").forEach(bar -> {
jdbcTemplate.update("insert into FOO (BAR) VALUES (?)", bar);
});
HashMap<String, String> row = new HashMap<>();
row.put("BAR", "d");
Number id = simpleJdbcInsert.executeAndReturnKey(row);
log.info("ID of d:{}", id.longValue());
}
public void listData() {
log.info("count:{}", jdbcTemplate.queryForObject("select count(*) from foo", Long.class));
List<String> list = jdbcTemplate.queryForList("select BAR from foo", String.class);
list.forEach(s -> log.info("Bar :{}", s));
List<Foo> fooList = jdbcTemplate.query("select * from foo", new RowMapper<Foo>() {
@Override
public Foo mapRow(ResultSet rs, int rowNum) throws SQLException {
return Foo.builder()
.id(rs.getLong(1))
.bar(rs.getString(2))
.build();
}
});
fooList.forEach(f -> log.info("Foo: {}", f));
}
}
- 创建BatchDao层,批量操作数据Dao层
@Repository
public class BatchFooDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public void batchUpdate() {
jdbcTemplate.batchUpdate("INSERT INTO FOO(BAR) VALUES (?)", new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, "b-" + i);
}
@Override
public int getBatchSize() {
return 2;
}
});
List<Foo> list = new ArrayList<>();
list.add(Foo.builder().id(100L).bar("b-100").build());
list.add(Foo.builder().id(101L).bar("b-101").build());
namedParameterJdbcTemplate.batchUpdate("INSERT INTO FOO (ID,BAR) VALUES(:id,:bar)", SqlParameterSourceUtils.createBatch(list));
}
}
- 调整主方法,Application
@SpringBootApplication
@Slf4j
public class SpringJdbcDemoApplication implements CommandLineRunner {
@Autowired
private FooDao fooDao;
@Autowired
private BatchFooDao batchFooDao;
public static void main(String[] args) {
SpringApplication.run(SpringJdbcDemoApplication.class, args);
}
@Bean
@Autowired
public SimpleJdbcInsert simpleJdbcInsert(JdbcTemplate jdbcTemplate) {
return new SimpleJdbcInsert(jdbcTemplate).withTableName("FOO").usingGeneratedKeyColumns("ID");
}
@Bean
@Autowired
public NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
@Override
public void run(String... args) throws Exception {
fooDao.insertData();
batchFooDao.batchUpdate();
fooDao.listData();
}
}
10什么是Spring的事务抽象
Spring的事务抽象
一致的事务模型
- JDBC/Hibernate/myBatis
- DataSource/JTA
事务抽象的核心接口
- PlatformTransactionManager
- HibernateTransactionManager
- jtaTranscationManager
TranscationDefinition
- Proagation
- lsolation
- Timeout
- Read only status
void commit(Transaction status) throws TranscationException;
void rollback(Transcation status) throws TranscationExeption;
TranscationStatus getTranscation(@Nullable TransactionDefinition definition) throws TransactionException;
事务传播特性
传播性 | 值 | 描述 |
---|---|---|
propagation_required | 0 | 当前有事务就用当前的,没有就用新的 |
propagation_supports | 1 | 事务可有可无,不是必须的 |
propagation_mandatory | 2 | 当前一定要有事务,不然就抛异常 |
propagation_requires_new | 3 | 无论是否有事务,都起个新的事务 |
propagation_not_supports | 4 | 不支持事务,按非事务方式运行 |
propagation_nerver | 5 | 不支持事务,如果有事务则抛异常 |
propagation_nested | 6 | 当前有事务在当前事务里再起一个事务 |
事务隔离特性
隔离性 | 值 | 脏读 | 不可重复读 | 幻读 | 说明 |
---|---|---|---|---|---|
isolation_read_uncommitted | 1 | √ | √ | √ | 未提交读 |
isolantion_read_commintted | 2 | × | √ | √ | 已提交读 |
isolantion_repeatable_read | 3 | × | × | √ | 可重复读 |
isolantion_serialiable | 4 | × | × | × | 串行化的 |
编程式事务
TransactionTemplate
- TransactionCallback
- TransactionCallbackWithoutResult
PlatformTransactionManager
- 可以传入TransactionDefinition进行定义
- HibernateTransactionManager
- jtaTranscationManager
TranscationDefinition
- Proagation
- lsolation
- Timeout
- Read only status
void commit(Transaction status) throws TranscationException;
void rollback(Transcation status) throws TranscationExeption;
TranscationStatus getTranscation(@Nullable TransactionDefinition definition) throws TransactionException;
事务传播特性
传播性 | 值 | 描述 |
---|---|---|
propagation_required | 0 | 当前有事务就用当前的,没有就用新的 |
propagation_supports | 1 | 事务可有可无,不是必须的 |
propagation_mandatory | 2 | 当前一定要有事务,不然就抛异常 |
propagation_requires_new | 3 | 无论是否有事务,都起个新的事务 |
propagation_not_supports | 4 | 不支持事务,按非事务方式运行 |
propagation_nerver | 5 | 不支持事务,如果有事务则抛异常 |
propagation_nested | 6 | 当前有事务在当前事务里再起一个事务 |
事务隔离特性
隔离性 | 值 | 脏读 | 不可重复读 | 幻读 | 说明 |
---|---|---|---|---|---|
isolation_read_uncommitted | 1 | √ | √ | √ | 未提交读 |
isolantion_read_commintted | 2 | × | √ | √ | 已提交读 |
isolantion_repeatable_read | 3 | × | × | √ | 可重复读 |
isolantion_serialiable | 4 | × | × | × | 串行化的 |
11什么是Spring编程是事务(下)
编程式事务
TransactionTemplate
- TransactionCallback
- TransactionCallbackWithoutResult
PlatformTransactionManager
- 可以传入TransactionDefinition进行定义
@SpringBootApplication
@Slf4j
public class ProgramaticTransactionDemoApplication implements CommandLineRunner{
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private JdbcTemplate jdbcTemplate;
public static void main(String[] args){
springApplication.run(ProgrammaticTransactionDemoApplication.class,args);
}
@Override
public void run(String... args) throws Exception{
log.info("COUNT BEFORE TRANSACTION:{}",getcount);
transactionTemplate.execute(new TransactionCallbackWithResult(){
@Override
protected void doInTrancationWithoutResult(Transcation transcation){
jdbcTemplate.execute("INSERT INTO FOO (ID,BAR) VALUES (1,'aaa')");
log.into("COUNT IN TRANSACTION:{}",getCount());
transactionStatus.setRollbackOnly();
}
});
log.info("COUNT AFTER TRANSACTION: {}",getCount());
}
private long getCount(){
return (long)jdbcTemplate.queryForList("SELECT COUNT(*) AS CNT FROM FOO").get(0).get(0).get("CNT")
}
}
事务声明
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cm6o0xIN-1630909447733)(https://note.youdao.com/yws/api/personal/file/2DF671A896504885A77D61CA7669D556?method=download&shareKey=e065241e048f5e55d6469b571eb359ca)]
基于注解的配置方式
开启事务注解的方式
- @EnableTransactionManagement
- tx:annotion-driven/
一些配置
- proxyTargetClass
- mode
- order
@Transactional
- transactionManager
- propagation
- isolation
- timeout
- readOnly
- 怎么判断回滚
@Component
public class FooServiceImpl implements FooService{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
@Transaction
public void insertRecord(){
jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('AAA')");
}
@Override
@Trancation(rollbackFor = RollbackException.class)
public void insertThenRollback() throws RollbackException {
jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES (BBB)");
throw new RollbackException();
}
@Override
public void invokeInsertThenRollback() throws RollbackExeception{
insertThenRollback();
}
}
了解SpringJDBC异常抽象
Spring的JDBC异常抽象
Spring会将数据操作的异常转换为DataAccessException
无论使用何种数据访问方式,都能使用一样的异常
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0lkTXqQL-1630909447736)(https://note.youdao.com/yws/api/personal/file/9FA8BCAF5B52479A87E6EBB9B406ABDC?method=download&shareKey=7128c73986e048b4f2d10f1d435eacaf)]
Spring是怎么认识那些错误码的
通过SQLErrorCodeSQLExceptionTranslator 解析错误码
ErrorCode 定义
- org/springframework/jdbc/support/sql-error-codes.xml
- Classpath 下的sql-error-codes.xml
定制错误码解析逻辑
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ubmIHSXT-1630909447737)(https://note.youdao.com/yws/api/personal/file/709C889114F546FA82BC58022D5ADE24?method=download&shareKey=8d8c9a522fcbb23c507ca54bfe3d9744)]
12了解Spring的JDBC异常抽象
13课程答疑(上)
14课程答疑(下)
最后
以上就是辛勤仙人掌为你收集整理的第二部分:Spring中的数据操作的全部内容,希望文章能够帮你解决第二部分:Spring中的数据操作所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复