Spring学习笔记(五):JDBCTemplate+事务管理
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版:
Kotlin版:
Spring学习笔记(五):JDBCTemplate+事务管理的更多相关文章
- Spring学习(五)事务管理
Spring 事务管理: 一.事务概念: 1.什么是事务? 事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消.也就是事务具有原子性,一个事务中的一系列的 ...
- Spring学习笔记五:Spring进行事务管理
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6776256.html 事务管理主要负责对持久化方法进行统一的提交或回滚,Spring进行事务管理即我们无需在 ...
- spring框架学习笔记7:事务管理及案例
Spring提供了一套管理项目中的事务的机制 以前写过一篇简单的介绍事务的随笔:http://www.cnblogs.com/xuyiqing/p/8430214.html 还有一篇Hibernate ...
- Spring 学习(五)--- 事务(未完成)
问题 : Spring 事务传播机制是怎么样的,在什么应用场景使用 事务是什么 我们使用的框架可能是Hibernate/JPA或者是Mybatis,都知道的底层是需要一个session/connect ...
- Hibernate学习笔记四:事务管理
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6768298.html 一:需要事务的Session操作 Session操作中,查询类操作是不需要事务就能生效 ...
- Spring学习笔记:jdbcTemplate和数据源配置
一.使用Spring框架jdbcTemplate实现数据库的增删改查 1.数据库 /* SQLyog Ultimate v8.32 MySQL - 5.7.19-log : Database - in ...
- Spring学习笔记三:Bean管理
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6775827.html 一:如何使用Spring获取对象 1:定义bean类:要按照注入方式来定义对应的bea ...
- Java框架spring 学习笔记(十八):事务管理(xml配置文件管理)
在Java框架spring 学习笔记(十八):事务操作中,有一个问题: package cn.service; import cn.dao.OrderDao; public class OrderSe ...
- Spring学习笔记:声明式事务管理增删改查业务
一.关于是事务 以方法为单位,进行事务控制:抛出异常,事务回滚. 最小的执行单位为方法.决定执行成败是通过是否抛出异常来判断的,抛出异常即执行失败 二.声明式事务: 声明式事务(declarative ...
- spring 学习(五):spring 事务
spring 学习(五):spring 事务 事务概要 一个数据库事务通常包含了一个序列的对数据库的读/写操作.它的存在包含有以下两个目的: 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同 ...
随机推荐
- 为什么Linux默认页大小是4KB
本文转载自为什么 Linux 默认页大小是 4KB 导语 我们都知道 Linux 会以页为单位管理内存,无论是将磁盘中的数据加载到内存中,还是将内存中的数据写回磁盘,操作系统都会以页面为单位进行操作, ...
- fail模块场景(ansible)
更多见博客 : https://blog.csdn.net/qq_35887546/article/details/105242720 创建剧本 /home/alice/ansible/lvm.yml ...
- flask启动常见问题1:sqlalchemy.exc.ArgumentError: Mapper mapped class UserCode->data_system_user_email could not assemble any primary key columns for mapped table 'data_system_user_email'
我的描述:当我编辑好flask以后,ORM映射数据库完成,启动项目时,发生现象: 解决: 看字面的意思是主键导致的错误,于是我查看了data_system_user_email的键参数配置,发现表没有 ...
- Java Socket编程基础及深入讲解
原文链接:https://www.cnblogs.com/yiwangzhibujian/p/7107785.html 原文写的特别好,非常详细,但是禁止转载,那我就不再复制粘贴了! socket实现 ...
- eclipse定制工具栏,修改工具栏
目前eclipse定制工具栏的入口就是window- customize perspective,在弹出的窗口中选择Tool Bar Visibility,选择要在工具栏中显示的快捷图标.注:在Too ...
- Nearby Service新特性:Wi-Fi分享
PART 1: Wi-Fi分享功能介绍 朋友来家里做客.顾客到店里用餐-当他们想要给自己的手机链接Wi-Fi时,总免不了询问Wi-Fi名称和密码..这种问密码和给密码的过程十分麻烦,常常还会有听错或者 ...
- 小白养成记——Java比较器Comparable和Comparator
一.使用情景 1. 调用Arrays.sort()方法或Collections.sort()方法对自定义类的对象排序 以Arrays.sort()为例.假定有如下自定义的Person类 1 publ ...
- Git 提交获取项目与提交项目 记录
首先去git官网下载版本安装:https://git-scm.com/downloads 在自己生产免密令牌,安装后用git程序导出. 1.自己在桌面或者某盘创建一个文件夹,在文件夹右键找到 GIt ...
- lambda表达式在python和c++中的异同
Lambda表达式是干么的?.lambda表达式首先是一个表达式,是一个函数对象一个匿名函数,但不是函数.现在流行语言例如:JS.PHP都支持一种和面向过程.面向对象并列的函数式编程,lambda就是 ...
- Java 常见对象 04
常见对象·Arrays 类和 包装类 数组高级冒泡排序原理图解 * A:画图演示 * 需求: 数组元素:{24, 69, 80, 57, 13} 请对数组元素进行排序 * 冒泡排序: 相邻元素两两比较 ...