1 概述
Spring
为开发者提供了 JDBCTemplate
,能够简化很多数据库操作相干的代码,本文次要介绍JDBCTemplate
的应用以及事务管理性能。
2 JDBC Template
2.1 配置
配置的话次要配置以下几项:
- 数据源:
org.springframework.jdbc.datasource.DriverManager.DataSource
- 数据库驱动:
com.cj.mysql.jdbc.Driver
,这里采纳的是MySQL 8
,留神MySQL 5.7
以下的驱动名字不同,另外若是其余数据库请对应批改 - 数据库
URL
:jdbc:mysql://localhost:3306/test
,MySQL
默认的3306
端口,数据库test
- 数据库用户名
- 数据库明码
JDBC
模板:org.springframework.jdbc.core.jdbcTemplate
参考配置如下:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="test"/>
<property name="password" value="test"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:component-scan base-package="pers.dao"/>
2.2 罕用办法
int update(String sql,Object args[])
:增 / 删 / 改操作,应用args
设置其中的参数,返回更新的行数List<T> query(String sql,RowMapper<T> rowMapper,Object []args)
:查问操作,rowMapper
将后果集映射到用户自定义的类中
2.3 示例
2.3.1 依赖
首先导入依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
MySQL
的版本请依据集体须要更改,或应用其余数据库的驱动。
2.3.2 配置文件
残缺配置文件如下:
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="test"/>
<property name="password" value="test"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:component-scan base-package="pers.dao"/>
</beans>
2.3.3 实体类
public class MyUser {
private Integer id;
private String uname;
private String usex;
}
2.3.4 数据拜访层
增加 @Repository
以及@RequiredArgsConstructor
:
@Repository
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TestDao {
private final JdbcTemplate template;
public int update(String sql,Object[] args)
{return template.update(sql,args);
}
public List<MyUser> query(String sql, Object[] args)
{RowMapper<MyUser> mapper = new BeanPropertyRowMapper<>(MyUser.class);
return template.query(sql,mapper,args);
}
}
因为间接应用 @Autowired
的话会提醒不举荐:
所以利用了 Lombok
的注解@RequiredArgsConstructor
,成果相当如下构造方法,只不过是简化了一点:
@Autowired
public TestDao(JdbcTemplate template)
{this.template = template;}
2.3.5 测试
测试之前先建表:
create table MyUser(
id INT AUTO_INCREMENT PRIMARY KEY ,
uname varchar(20),
usex varchar(20)
)
测试类:
public class Main {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
TestDao dao = (TestDao)context.getBean("testDao");
String insertSql = "insert into MyUser(uname,usex) values(?,?)";
String[] param1 = {"chenhengfa1","男"};
String[] param2 = {"chenhengfa2","男"};
String[] param3 = {"chenhengfa3","男"};
String[] param4 = {"chenhengfa4","男"};
dao.update(insertSql,param1);
dao.update(insertSql,param2);
dao.update(insertSql,param3);
dao.update(insertSql,param4);
String selectSql = "select * from MyUser";
List<MyUser> list = dao.query(selectSql,null);
for(MyUser mu:list)
{System.out.println(mu);
}
}
}
输入:
如果出现异常或插入不胜利等其余状况,请查看 SQL
语句是否编写正确,包含表名以及字段名。
3 事务管理
Spring
中的事务管理有两种办法:
- 编程式事务管理:代码中显式调用
beginTransaction
、commit
、rollback
等就是编程式事务管理 - 申明式事务管理:通过
AOP
实现,不须要通过编程形式治理事务,因而不须要再业务逻辑代码中掺杂事务处理的代码,开发更加简略,便于前期保护
上面先来看一下编程式事务管理的实现。
3.1 编程式事务管理
编程式事务管理的配置又有两种办法:
- 基于底层
API
- 基于
TransactionTemplate
须要的依赖如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
3.1.1 底层 API
实现
依据 PlatformTransactionManager
、TransactionDefinition
、TransactionStatus
几个外围接口,通过编程形式进行事务管理,首先配置事务管理器:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
接着批改数据库拜访类:
@Repository
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TestDao {
private final JdbcTemplate template;
private final DataSourceTransactionManager manager;
public int update(String sql,Object[] args)
{return template.update(sql,args);
}
public List<MyUser> query(String sql,Object[] args)
{RowMapper<MyUser> mapper = new BeanPropertyRowMapper<>(MyUser.class);
return template.query(sql,mapper,args);
}
public void testTransaction()
{TransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus status = manager.getTransaction(definition);
String message = "执行胜利,没有事务回滚";
try
{
String sql1 = "delete from MyUser";
String sql2 = "insert into MyUser(id,uname,usex) values(?,?,?)";
Object [] param2 = {1,"张三","男"};
template.update(sql1);
template.update(sql2,param2);
template.update(sql2,param2);
manager.commit(status);
}
catch (Exception e)
{e.printStackTrace();
manager.rollback(status);
message = "主键反复,事务回滚";
}
System.out.println(message);
}
}
3.1.1.1 事务定义
TransactionDefinition
是事务定义,是一个接口:
次要定义了:
- 事务隔离级别
- 事务流传行为
- 事务超时工夫
- 是否为只读事务
而 DefaultTransactionDefinition
就是下面属性的一些默认配置,比方:
也就是定义了:
- 流传行为为
0
:也就是常量PROPAGATION_REQUIREDE
,示意如果以后存在一个事务,则退出以后事务,如果不存在任何事务,就创立一个新事务 - 隔离级别为
-1
:这个也是TransactionDefinition
的默认参数,示意应用数据库的默认隔离级别,通常状况下为Read Committed
- 超时为
-1
:默认设置不超时,如须要设置超时请调用setTimeout
办法,比方如果设置为了60
,那么相当于如果操作工夫超过了60s
,而且前面还波及到CRUD
操作,那么会抛出超时异样并回滚,如果超时操作的前面没有波及到CRUD
操作,那么不会回滚 - 只读事务为
false
:默认为false
,然而该变量不是表明“不能”进行批改等操作,而是一种暗示,如果不蕴含批改操作,那么JDBC
驱动和数据库就有可能针对该事务进行一些特定的优化
3.1.1.2 具体执行流程
具体执行流程如下:
- 定义事务:实例类为
DefaultTransactionDefinition
- 开启事务:通过
getTransaction(TransactionDefinition)
开启 - 执行业务办法
- 依据业务办法是否出现异常手动调用
DataSourceTransaction
的commit(TransactionStatus)
进行提交 - 出现异常调用
rollback(TransactionStatus)
进行回滚
测试如下:
3.1.2 基于TransactionTemplate
步骤:
- 通过调用
TransactionTemplate
的execute
实现 execute
承受一个TransactionCallback
接口参数TransactionCallback
定义了一个doInTransaction
办法- 通常以匿名外部类的形式实现
TransactionCallback
接口,在其中的doInTransaction
编写业务逻辑代码 doInTransaction
有一个TransactionStatus
的参数,能够调用setRollbackOnly
进行回滚
默认的回滚规定如下:
- 如果抛出未查看异样或者手动调用
setRollbackOnly
,则回滚 - 如果执行实现或抛出查看异样,则提交事务
示例如下,首先编写配置文件对 Bean
进行注入:
<!-- 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 事务模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"/>
</bean>
其次批改数据拜访类,增加一个测试方法:
public void testTransactionTemplate()
{System.out.println(transactionTemplate.execute((TransactionCallback<Object>) transactionStatus -> {
String deleteSql = "delete from MyUser";
String insertSql = "insert into MyUser(id,uname,usex) values(?,?,?)";
Object[] parm = {1, "张三", "男"};
try {template.update(deleteSql);
template.update(insertSql, parm);
template.update(insertSql, parm);
} catch (Exception e) {
message = "主键反复,事务回滚";
e.printStackTrace();}
return message;
}));
}
大部分代码与第一个例子相似就不解释了,后果也是因为主键反复出现异常,造成事务回滚:
3.2 申明式事务管理
Spring
申明式事务管理通过 AOP
实现,实质是在办法前后进行拦挡,在指标办法开始之前创立或退出一个事务,执行指标办法实现之后依据执行状况提交或回滚事务。相比起编程式事务管理,申明式最大的长处就是不须要通过编程的形式治理事务,业务逻辑代码无需混淆事务代码,然而惟一有余的中央就是最细粒度只能作用到办法上,而不能做到代码块级别。
实现形式有如下两种:
- 基于
XML
实现 - 基于
@Transactional
实现
3.2.1 基于XML
Spring
提供了 tx
命令空间来配置事务:
<tx:advice>
:配置事务告诉,个别须要指定id
以及transaction-manager
<tx:attributes>
:配置多个<tx:method>
指定执行事务的细节
3.2.1.1 配置文件
残缺配置文件如下:
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="test"/>
<property name="password" value="test"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:component-scan base-package="pers.dao"/>
<!-- 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"/>
</bean>
<!-- 申明式事务 -->
<tx:advice id="myAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 任意办法 -->
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<!--aop 配置,具体能够看笔者之前的文章 -->
<aop:config>
<!-- 定义切点,执行 testXMLTranscation()时进行加强 -->
<aop:pointcut id="txPointCut" expression="execution(* pers.dao.TestDao.testXMLTransaction())"/>
<!-- 切面 -->
<aop:advisor advice-ref="myAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
3.2.1.2 测试
测试方法如下:
public void testXMLTransaction()
{
String deleteSql = "delete from MyUser";
String saveSql = "insert into MyUser(id,uname,usex) values(?,?,?)";
Object [] parm = {1,"张三","男"};
template.update(deleteSql);
template.update(saveSql,parm);
template.update(saveSql,parm);
}
运行后果:
能够看到提醒主键反复了。
3.2.2 基于@Transactional
@Transactional
个别作用于类上,使得该类所有 public
办法都具备该类型的事务属性。上面创立一个示例。
3.2.2.1 配置文件
将上一个例子中的 <aop:config>
以及 <tx:advice>
正文掉,同时增加:
<!-- 事务管理的注解驱动器 -->
<tx:annotation-driven transaction-manager="txManager"/>
3.2.2.2 测试
测试方法与上一个例子统一,后果也是如此:
4 参考源码
Java
版:
- Github
- 码云
- CODE.CHINA
Kotlin
版:
- Github
- 码云
- CODE.CHINA