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以下的驱动名字不同,另外若是其他数据库请对应修改
  • 数据库URLjdbc:mysql://localhost:3306/testMySQL默认的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/beanshttp://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中的事务管理有两种方法:

  • 编程式事务管理:代码中显式调用beginTransactioncommitrollback等就是编程式事务管理
  • 声明式事务管理:通过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实现

根据PlatformTransactionManagerTransactionDefinitionTransactionStatus几个核心接口,通过编程方式进行事务管理,首先配置事务管理器:

<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)开启
  • 执行业务方法
  • 根据业务方法是否出现异常手动调用DataSourceTransactioncommit(TransactionStatus)进行提交
  • 出现异常调用rollback(TransactionStatus)进行回滚

测试如下:

3.1.2 基于TransactionTemplate

步骤:

  • 通过调用TransactionTemplateexecute实现
  • 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/cachehttp://www.springframework.org/schema/cache/spring-cache.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://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
  • 码云
  • GitCode

Kotlin版:

  • Github
  • 码云
  • GitCode

Spring学习笔记(五):JDBCTemplate+事务管理相关推荐

  1. 乐优商城学习笔记五-商品规格管理

    0.学习目标 了解商品规格数据结构设计思路 实现商品规格查询 了解SPU和SKU数据结构设计思路 实现商品查询 了解商品新增的页面实现 独立编写商品新增后台功能 1.商品规格数据结构 乐优商城是一个全 ...

  2. 【Spring学习笔记 九】Spring声明式事务管理实现机制

    什么是事务?事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用,关乎数据准确性的地方我们一定要用到事务,防止业务逻辑出错. 什么是事务管理,事务管理对于企业应用而言至 ...

  3. MySQL学习笔记07【事务、用户管理和权限管理】

    MySQL 文档-黑马程序员(腾讯微云):https://share.weiyun.com/RaCdIwas 1-MySQL基础.pdf.2-MySQL约束与设计.pdf.3-MySQL多表查询与事务 ...

  4. Spring Boot 框架学习笔记(五)( SpringSecurity安全框架 )

    Spring Boot 框架学习笔记(五) SpringSecurity安全框架 概述 作用 开发示例: 1. 新建项目 2. 引入依赖 3. 编写`SecurityConfig`类,实现认证,授权, ...

  5. spring框架学习 - Data Access之 事务管理 - 声明式事务管理

    接上一篇博客:https://blog.csdn.net/qq_43605444/article/details/122085016?spm=1001.2014.3001.5502 4.声明式事务管理 ...

  6. Spring学习笔记之MyBatis

    系列文章目录 Spring学习笔记 之 Springhttps://blog.csdn.net/weixin_43985478/article/details/124411746?spm=1001.2 ...

  7. spring学习笔记06-spring整合junit(出现的问题,解决的思路)

    spring学习笔记06-spring整合junit(出现的问题,解决的思路) 文章目录 spring学习笔记06-spring整合junit(出现的问题,解决的思路) 3.1测试类中的问题和解决思路 ...

  8. Spring 学习笔记----->AOP

    Spring 学习笔记----->AOP 代理模式 为什么学代理模式? 因为这就是Spring Aop的底层 代理模式的分类: 静态代理 动态代理 静态代理 生活用的例子: 房东 public ...

  9. 一箭双雕 刷完阿里P8架构师spring学习笔记+源码剖析,涨薪8K

    关于Spring的叙述: 我之前死磕spring的时候,刷各种资料看的我是一头雾水的,后面从阿里的P8架构师那里拿到这两份资料,从源码到案例详细的讲述了spring的各个细节,是我学Spring的启蒙 ...

  10. JavaEE——Spring学习笔记03【AOP开发】

    JavaEE--Spring学习笔记01[Ioc开发的模式] JavaEE--Spring学习笔记02[Spring和Mybatis的整合] JavaEE--Spring学习笔记03[AOP开发] J ...

最新文章

  1. BUUCTF 新年快乐 内涵的软件 Java逆向解密 刮开有奖
  2. android-6.0不支持FloatMath.sqrt(x * x + y * y)
  3. python的os.path.join
  4. 用JQuery中的Ajax方法获取web service等后台程序中的方法
  5. Linux 用户态与内核态的交互——netlink 篇
  6. Java Servlet(八):EL自定义函数
  7. vb中多个串口通讯_串口服务器的原理及应用!
  8. 力扣—— 224. 基本计算器(困难)
  9. Perl用LWP实现GET/POST数据发送 原
  10. 目标高盛,卡方科技用智能金融科技撬动国内量化投资
  11. 实施定性风险分析-规划过程组
  12. Oracle LOB
  13. java调用ip138接口查询ip地址,iP查询接口Javascript代码示例 iP地址查询接口Javascript代码示例 iP138查询网...
  14. 股票振幅榜查询易语言代码
  15. 高仿小米商城项目,我爱了!
  16. 松鼠Ai辅助公校教育,开启智慧教育3.0
  17. 【推荐系统】【论文阅读笔记】【survey】A Survey on Session-based Recommender Systems基于会话的推荐系统综述
  18. [THE_PLAN]八月份的第一抹阳光
  19. 在一个字符串中查找另一个字符串出现的位置
  20. 【Linux】第十一篇:线程安全(互斥锁,死锁,条件变量)

热门文章

  1. PAT甲级真题目录(按题型整理)(转自柳神)
  2. 常见电子邮件英文缩写
  3. android 手势放缩_Android 手势识别—缩放
  4. 安装过程中弹出错误信息,Xshell4提示nslicense.dll无法安装成功
  5. iPhone14和14pro的区别
  6. JBoss学习和应用
  7. VUE中created被重复调用(每次进入页面之后都会调用created)
  8. RocksDB 架构
  9. windows7安装打印机提示“本地打印后台处理程序服务没有运行”
  10. Flask-中session的工作机制和session操作