Spring学习笔记(五):JDBCTemplate+事务管理 您所在的位置:网站首页 java使用事务实现员工工资上调 Spring学习笔记(五):JDBCTemplate+事务管理

Spring学习笔记(五):JDBCTemplate+事务管理

2024-07-15 03:21| 来源: 网络整理| 查看: 265

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

参考配置如下:

2.2 常用方法 int update(String sql,Object args[]):增/删/改操作,使用args设置其中的参数,返回更新的行数List query(String sql,RowMapper rowMapper,Object []args):查询操作,rowMapper将结果集映射到用户自定义的类中 2.3 示例 2.3.1 依赖

首先导入依赖:

org.springframework spring-jdbc 5.2.9.RELEASE mysql mysql-connector-java 8.0.21

MySQL的版本请根据个人需要更改,或使用其他数据库的驱动。

2.3.2 配置文件

完整配置文件如下:

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 query(String sql, Object[] args) { RowMapper 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 list = dao.query(selectSql,null); for(MyUser mu:list) { System.out.println(mu); } } }

输出:

在这里插入图片描述

如果出现异常或插入不成功等其他情况,请检查SQL语句是否编写正确,包括表名以及字段名。

3 事务管理

Spring中的事务管理有两种方法:

编程式事务管理:代码中显式调用beginTransaction、commit、rollback等就是编程式事务管理声明式事务管理:通过AOP实现,不需要通过编程方式管理事务,因此不需要再业务逻辑代码中掺杂事务处理的代码,开发更加简单,便于后期维护

下面先来看一下编程式事务管理的实现。

3.1 编程式事务管理

编程式事务管理的配置又有两种方法:

基于底层API基于TransactionTemplate

需要的依赖如下:

org.springframework spring-tx 5.2.9.RELEASE org.springframework spring-expression 5.2.9.RELEASE org.springframework spring-aop 5.2.9.RELEASE org.aspectj aspectjweaver 1.9.6 runtime org.springframework spring-aspects 5.2.9.RELEASE 3.1.1 底层API实现

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

接着修改数据库访问类:

@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 query(String sql,Object[] args) { RowMapper 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进行注入:

其次修改数据访问类,添加一个测试方法:

public void testTransactionTemplate() { System.out.println(transactionTemplate.execute((TransactionCallback) 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命令空间来配置事务:

:配置事务通知,一般需要指定id以及transaction-manager:配置多个指定执行事务的细节 3.2.1.1 配置文件

完整配置文件如下:

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 配置文件

将上一个例子中的以及注释掉,同时添加:

在这里插入图片描述

3.2.2.2 测试

测试方法与上一个例子一致,结果也是如此:

在这里插入图片描述

4 参考源码

Java版:

Github码云GitCode

Kotlin版:

Github码云GitCode


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有