Spring JdbcTemplate 和 事务
创始人
2024-05-24 18:34:56
0

JdbcTemplate概述

JdbcTemplate是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和,操作nosql数据库的RedisTemplate,操作消息队列的JmsTemplate等等。
在这里插入图片描述
按如下项目结构准备 maven jar项目即可
在这里插入图片描述
导入依赖

 org.springframeworkspring-context5.3.5org.springframeworkspring-aspects5.3.5aopallianceaopalliance1.0com.alibabadruid1.1.10mysqlmysql-connector-java8.0.22org.springframeworkspring-jdbc5.3.5org.springframeworkspring-tx5.3.5org.springframeworkspring-orm5.3.5commons-loggingcommons-logging1.2junitjunit4.13.1testorg.projectlomboklombok1.18.12provided

准备JDBC.properties

jdbc_username=root
jdbc_password=root
jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true

准备applicationContext.xml




单个数据操作
准备实体类

package com.msb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;@AllArgsConstructor
@NoArgsConstructor
@Data
public class Emp implements Serializable{private Integer empno;private String ename;private String job;private Integer mgr;private Date hiredate;private Double sal;private Double comm;private Integer deptno;
}

准备service层接口和实现类

package com.msb.service;
import com.msb.pojo.Emp;
import java.util.List;public interface EmpService {int findEmpCount();Emp findByEmpno(int empno);List findByDeptno(int deptno);int  addEmp(Emp emp);int updateEmp(Emp emp);int deleteEmp( int empno);
}
package com.msb.service.impl;
import com.msb.dao.EmpDao;
import com.msb.pojo.Emp;
import com.msb.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class EmpServiceImpl implements EmpService {@Autowiredprivate EmpDao empDao;@Overridepublic int findEmpCount() {return empDao.findEmpCount();}@Overridepublic Emp findByEmpno(int empno) {return empDao.findByEmpno( empno);}@Overridepublic List findByDeptno(int deptno) {return empDao.findByDeptno( deptno);}@Overridepublic int addEmp(Emp emp) {return empDao.addEmp(emp);}@Overridepublic int updateEmp(Emp emp) {return empDao.updateEmp(emp);}@Overridepublic int deleteEmp(int empno) {return empDao.deleteEmp(empno);}
}

准备dao层接口和实现类

package com.msb.dao;
import com.msb.pojo.Emp;
import java.util.List;public interface EmpDao {int findEmpCount();Emp findByEmpno(int empno);List findByDeptno(int deptno);int addEmp(Emp emp);int updateEmp(Emp emp);int deleteEmp(int empno);
}
package com.msb.dao.impl;
import com.msb.dao.EmpDao;
import com.msb.pojo.Emp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;@Repository
public class EmpDaoImpl implements EmpDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int findEmpCount() {/*查询员工个数* queryForObject 两个参数* 1 SQL语句* 2 返回值类型** */Integer empCount = jdbcTemplate.queryForObject("select count(1) from emp", Integer.class);return empCount;}@Overridepublic Emp findByEmpno(int empno) {/** 查询单个员工对象* queryForObject三个参数* 1 SQL语句* 2 RowMapper接口的实现类对象,用于执行返回的结果用哪个类来进行封装 ,实现类为BeanPropertyRowMapper* 3 SQL语句中需要的参数 (可变参数)* */BeanPropertyRowMapper rowMapper =new BeanPropertyRowMapper<>(Emp.class);Emp emp = jdbcTemplate.queryForObject("select * from emp where empno =?", rowMapper, empno);return emp;}@Overridepublic List findByDeptno(int deptno) {/** 查询单个员工对象* query三个参数* 1 SQL语句* 2 RowMapper接口的实现类对象,用于执行返回的结果用哪个类来进行封装 ,实现类为BeanPropertyRowMapper* 3 SQL语句中需要的参数 (可变参数)* */BeanPropertyRowMapper rowMapper =new BeanPropertyRowMapper<>(Emp.class);List emps = jdbcTemplate.query("select * from emp where deptno =?", rowMapper, deptno);return emps;}@Overridepublic int addEmp(Emp emp) {/*增删改* 统统用update方法 两个参数* 1 SQL语句* 2 SQL语句需要的参数 (可变参数)** */String sql ="insert into emp values(DEFAULT ,?,?,?,?,?,?,?)";Object[] args ={emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno()};return jdbcTemplate.update(sql,args);}@Overridepublic int updateEmp(Emp emp) {String sql ="update emp set ename =? , job =?, mgr=? , hiredate =?, sal=?, comm=?, deptno =? where empno =?";Object[] args ={emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno(),emp.getEmpno()};return jdbcTemplate.update(sql,args);}@Overridepublic int deleteEmp(int empno) {String sql ="delete  from emp where empno =?";return jdbcTemplate.update(sql, empno);}
}

测试代码

package com.msb.test;
import com.msb.pojo.Emp;
import com.msb.service.EmpService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;
import java.util.List;public class Test1 {@Testpublic void testEmpService(){ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");EmpService empService = context.getBean(EmpService.class);// 查询员工个数/*int empCount = empService.findEmpCount();System.out.println(empCount);*/// 根据员工编号查询员工对象/* Emp byEmpno = empService.findByEmpno(7521);System.out.println(byEmpno);*//*根据部门编号查询多个员工对象集合*//*List emps = empService.findByDeptno(20);emps.forEach(System.out::println);*//*增加员工信息*//*int rows = empService.addEmp(new Emp(null, "TOM", "SALESMAN", 7521, new Date(), 2000.0, 100.0, 10));System.out.println(rows);*//*根据员工编号修改员工信息*//*int rows = empService.updateEmp(new Emp(7939, "JERRY", "MANAGER", 7839, new Date(), 3000.0, 0.0, 20));System.out.println(rows);*//*根据员工编号删除员工信息*//*int rows = empService.deleteEmp(7939);System.out.println(rows);*/}
}

批量操作
1 批量增加
2 批量修改
3 批量删除

实体类

package com.msb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;@AllArgsConstructor
@NoArgsConstructor
@Data
public class Dept implements Serializable {private Integer deptno;private String dname;private String loc;
}

DeptService

package com.msb.service;
import com.msb.pojo.Dept;
import java.util.List;public interface DeptService {int[] deptBatchAdd(List depts);int[] deptBatchUpdate(List depts);int[] deptBatchDelete(List deptnos);
}
package com.msb.service.impl;
import com.msb.dao.DeptDao;
import com.msb.pojo.Dept;
import com.msb.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptDao deptDao;@Overridepublic int[] deptBatchAdd(List depts) {return deptDao.deptBatchAdd(depts);}@Overridepublic int[] deptBatchUpdate(List depts) {return  deptDao.deptBatchUpdate(depts);}@Overridepublic int[] deptBatchDelete(List deptnos) {return  deptDao.deptBatchDelete(deptnos);}
}

DeptDao

package com.msb.dao;
import com.msb.pojo.Dept;
import java.util.List;public interface DeptDao {int[] deptBatchAdd(List depts);int[] deptBatchUpdate(List depts);int[] deptBatchDelete(List deptnos);
}
package com.msb.dao.impl;
import com.msb.dao.DeptDao;
import com.msb.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.LinkedList;
import java.util.List;@Repository
public class DeptDaoImpl implements DeptDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int[] deptBatchAdd(List depts) {String sql ="insert into dept values(DEFAULT,?,?)";List args =new LinkedList<>();for (Dept dept : depts) {Object[] arg ={dept.getDname(),dept.getLoc()};args.add(arg);}return jdbcTemplate.batchUpdate(sql, args);}@Overridepublic int[] deptBatchUpdate(List depts) {String sql ="update dept set dname =? ,loc =? where deptno=?";List args =new LinkedList<>();for (Dept dept : depts) {Object[] arg ={dept.getDname(),dept.getLoc(),dept.getDeptno()};args.add(arg);}return jdbcTemplate.batchUpdate(sql, args);}@Overridepublic int[] deptBatchDelete(List deptnos) {String sql ="delete from dept where deptno =?";List args =new LinkedList<>();for (Integer deptno : deptnos) {Object[] arg ={deptno};args.add(arg);}return jdbcTemplate.batchUpdate(sql, args);}
}

测试

package com.msb.test;
import com.msb.pojo.Dept;
import com.msb.service.DeptService;
import com.msb.service.EmpService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class Test2 {@Testpublic void testBatchAdd(){ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");DeptService deptService = context.getBean(DeptService.class);List depts =new ArrayList<>();for (int i = 0; i < 10; i++) {depts.add(new Dept(null,"name"+i,"loc"+i));}int[] ints = deptService.deptBatchAdd(depts);System.out.println(Arrays.toString(ints));}@Testpublic void testBatchUpdate(){ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");DeptService deptService = context.getBean(DeptService.class);List depts =new ArrayList<>();for (int i = 51; i <=60; i++) {depts.add(new Dept(i,"newname","newLoc"));}int[] ints = deptService.deptBatchUpdate(depts);System.out.println(Arrays.toString(ints));}@Testpublic void testBatchDelete(){ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");DeptService deptService = context.getBean(DeptService.class);List deptnos =new ArrayList<>();for (int i = 51; i <=69; i++) {deptnos.add(i);}int[] ints = deptService.deptBatchDelete(deptnos);System.out.println(Arrays.toString(ints));}
}

事务

1.事务的概念

事务(Transaction)指的是一个操作序列,该操作序列中的多个操作要么都做,要么都不做,是一个不可分割的工作单位,是数据库环境中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。

目前常用的存储引擎有InnoDB(MySQL5.5以后默认的存储引擎)和MyISAM(MySQL5.5之前默认的存储引擎),其中InnoDB支持事务处理机制,而MyISAM不支持。

2.事务的特性

事务处理可以确保除非事务性序列内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的序列,可以简化错误恢复并使应用程序更加可靠。

但并不是所有的操作序列都可以称为事务,这是因为一个操作序列要成为事务,必须满足事务的原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。这四个特性简称为ACID特性。
在这里插入图片描述

  1. 原子性

原子是自然界最小的颗粒,具有不可再分的特性。事务中的所有操作可以看做一个原子,事务是应用中不可再分的最小的逻辑执行体。

使用事务对数据进行修改的操作序列,要么全部执行,要么全不执行。通常,某个事务中的操作都具有共同的目标,并且是相互依赖的。如果数据库系统只执行这些操作中的一部分,则可能会破坏事务的总体目标,而原子性消除了系统只处理部分操作的可能性。

2)一致性

一致性是指事务执行的结果必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库中只包含事务成功提交的结果时,数据库处于一致性状态。一致性是通过原子性来保证的。

例如:在转账时,只有保证转出和转入的金额一致才能构成事务。也就是说事务发生前和发生后,数据的总额依然匹配。

  1. 隔离性

隔离性是指各个事务的执行互不干扰,任意一个事务的内部操作对其他并发的事务,都是隔离的。也就是说:并发执行的事务之间既不能看到对方的中间状态,也不能相互影响。

例如:在转账时,只有当A账户中的转出和B账户中转入操作都执行成功后才能看到A账户中的金额减少以及B账户中的金额增多。并且其他的事务对于转账操作的事务是不能产生任何影响的。

4)持久性

持久性指事务一旦提交,对数据所做的任何改变,都要记录到永久存储器中,通常是保存进物理数据库,即使数据库出现故障,提交的数据也应该能够恢复。但如果是由于外部原因导致的数据库故障,如硬盘被损坏,那么之前提交的数据则有可能会丢失。

3.事务的并发问题

脏读(Dirty read)

当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
在这里插入图片描述
不可重复读

(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
在这里插入图片描述
幻读

(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

在这里插入图片描述
不可重复度和幻读区别:

不可重复读的重点是修改,幻读的重点在于新增或者删除。

解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

例1(同样的条件, 你读取过的数据, 再次读取出来发现值不一样了 ):事务1中的A先生读取自己的工资为 1000的操作还没完成,事务2中的B先生就修改了A的工资为2000,导 致A再读自己的工资时工资变为 2000;这就是不可重复读。

例2(同样的条件, 第1次和第2次读出来的记录数不一样 ):假某工资单表中工资大于3000的有4人,事务1读取了所有工资大于3000的人,共查到4条记录,这时事务2又插入了一条工资大于3000的记录,事务1再次读取时查到的记录就变为了5条,这样就导致了幻读

4.事务的隔离级别

事务的隔离级别用于决定如何控制并发用户读写数据的操作。数据库是允许多用户并发访问的,如果多个用户同时开启事务并对同一数据进行读写操作的话,有可能会出现脏读、不可重复读和幻读问题,所以MySQL中提供了四种隔离级别来解决上述问题。

事务的隔离级别从低到高依次为READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ以及SERIALIZABLE,隔离级别越低,越能支持高并发的数据库操作。
在这里插入图片描述
spring中可以使用如下方式实现事务的控制

1 编程式(不推荐)

2 声明式(掌握)

1)注解(简单,必会)

2)XML配置(繁琐,了解)

demo搭建
通过张三给李四转账案例演示事务的控制
1 数据库中准备表格
在这里插入图片描述
applicationContext.xml
jdbc.properties 如上边项目配置
项目中准备实体类

package com.msb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;@AllArgsConstructor
@NoArgsConstructor
@Data
public class Account implements Serializable {private Integer id;private String name;private Integer money;
}

准备DAO层,创建一个根据id修改money的方法

package com.msb.dao;public interface AccountDao {int transMoney(int id,int money);
}
package com.msb.dao.impl;
import com.msb.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;@Repository
public class AccountDaoImpl implements AccountDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int transMoney(int id, int money) {String sql ="update account set money =money +? where id =?";return jdbcTemplate.update(sql,money,id);}
}

准备Service,创建一个转账的业务方法

package com.msb.service;public interface AccountService {int transMoney(int from ,int to,int money);
}
package com.msb.service.impl;
import com.msb.dao.AccountDao;
import com.msb.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Overridepublic int transMoney(int from, int to, int money) {int rows=0;rows+=accountDao.transMoney(from, 0 - money);       rows+=accountDao.transMoney(to, money);        return rows;}
}

测试代码,测试转账

package com.msb.test;
import com.msb.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestTx {@Test()public void testTransaction(){ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");AccountService accountService = context.getBean(AccountService.class);int rows = accountService.transMoney(1, 2, 100);System.out.println(rows);}}

基于注解方式实现

Spring声明式事务的实现方式,底层就是AOP,AOP的底层就是动态代理

Spring事务管理相关的API

事务管理器接口: PlatformTransactionManager 针对不同的框架,提供了不同的实现类
在这里插入图片描述
注解方式实现事务控制
在applicationContext.xml配置事务相关的配置




在Service层中添加事务的注解

package com.msb.service.impl;
import com.msb.dao.AccountDao;
import com.msb.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
//@Transactional //加在类上,代表类中的所有方法都添加了事务控制
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Override@Transactional// 放在方法上,就是仅仅对当前方法增加了事务控制public int transMoney(int from, int to, int money) {int rows=0;rows+=accountDao.transMoney(from, 0 - money);int i =1/0;rows+=accountDao.transMoney(to, money);return rows;}
}

再次测试,就算是service方法运行出现异常,自动会回滚,如果没有,那么自动提交

@Transactional 注解的一些参数和参数的含义
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_UNCOMMITTED,readOnly = true,rollbackFor = ClassCastException.class,noRollbackFor = NullPointerException.class,timeout = 10)

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {@AliasFor("transactionManager")String value() default "";@AliasFor("value")String transactionManager() default "";String[] label() default {};Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default -1;String timeoutString() default "";boolean readOnly() default false;Class[] rollbackFor() default {};String[] rollbackForClassName() default {};Class[] noRollbackFor() default {};String[] noRollbackForClassName() default {};
}

propagation 事务的传播行为(面试)
多事务方法之间调用,事务是如何管理的
在这里插入图片描述
在这里插入图片描述
如果service层 add方法调用了 addDept和addEmp两个方法

PROPAGATION_REQUIRED
如果add方法有事务,那么addDept和addEmp就加入到add方法里的事务
如果add方法没有事务,那么就新建一个事务,将addDept和addEmp加入到这个新的事务中

PROPAGATION_REQUIRES_NEW
无论add是否有事务,都建立一个新的事务,所有的方法都加入到新的事务中,add原来的事务就不用了

isolation 事务的隔离级别

  1. DEFAULT (默认)
    这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。
    MySQL默认REPEATABLE_READ
    Oracle默认READ_COMMITTED

  2. READ_UNCOMMITTED (读未提交)
    这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

  3. READ_COMMITTED (读已提交)
    保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

  4. REPEATABLE_READ (可重复读)
    这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。

  5. SERIALIZABLE(串行化)
    这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。

timeout 超时时间
事务一定要在多长时间之内提交,如果不提交就会回滚

readOnly 只读事务
事务是否只能读取数据库的数据,如果为true,则不允许进行增删改

rollbackFor 指定发生回滚的异常
当方法发生哪些异常时才会回滚

noRollbackFor 指定不发生回滚的异常
当方法发生哪些异常时,不会回滚

事务的xml配置




创建零配置文件事务(配置类配置)

package com.msb.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;@Configuration  // 配置类标志注解
@ComponentScan(basePackages = "com.msb") // spring包扫描
@PropertySource("classpath:jdbc.properties") // 读取属性配置文件
@EnableTransactionManagement // 开启事务注解
public class SpringConfig {@Value("${jdbc_driver}")private String driver;@Value("${jdbc_url}")private String url;@Value("${jdbc_username}")private String username;@Value("${jdbc_password}")private String password;/*创建数据库连接池*/@Beanpublic DruidDataSource getDruidDataSource(){DruidDataSource dataSource=new DruidDataSource();dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}no/*创建JdbcTemplate对象*/@Beanpublic JdbcTemplate getJdbcTemplate(DataSource dataSource){JdbcTemplate jdbcTemplate=new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}/*创建事务管理器*/@Beanpublic PlatformTransactionManager getPlatformTransactionManager(DataSource dataSource){DataSourceTransactionManager transactionManager =new DataSourceTransactionManager();transactionManager.setDataSource(dataSource);return transactionManager;}
}

测试代码

    @Test()public void testTransaction3(){ApplicationContext context =new AnnotationConfigApplicationContext(SpringConfig.class);AccountService accountService = context.getBean(AccountService.class);int rows = accountService.transMoney(1, 2, 100);System.out.println(rows);}

附Spring测试组件

spring5框架自带了通用的日志封装,也可以整合自己的日志
1)spring移除了 LOG4jConfigListener,官方建议使用log4j2
2)spring5整合log4j2
导入log4j2依赖

        org.apache.logging.log4jlog4j-slf4j-impl2.14.0test

在resources目录下准备log4j2.xml的配置文件




spring5关于测试工具的支持

整合junit4
依赖的jar

        junitjunit4.13.1testorg.springframeworkspring-test5.3.5test

测试代码编写方式

//省略了加载容器配置文件代码编写

package com.msb.test;
import com.msb.config.SpringConfig;
import com.msb.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.lang.Nullable;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)// 指定测试支持类
@ContextConfiguration("classpath:applicationContext.xml")// 指定核心配置文件位置
public class Test2 {@Autowired // 注入要获取的beanprivate  AccountService accountService;@Test()public void testTransaction(){int rows = accountService.transMoney(1, 2, 100);System.out.println(rows);}
}

整合junit5

依赖的jar

 org.junit.jupiterjunit-jupiter-api5.7.0test

测试代码编写方式

package com.msb.test;
import com.msb.service.AccountService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;/*使用ExtentWith和ContextConfiguration注解*/
/*@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:applicationContext.xml")*/
// 使用复合注解代替前两个注解
@SpringJUnitConfig(locations = "classpath:applicationContext.xml")
public class Test3 {@Autowired // 注入要获取的beanprivate  AccountService accountService;@Testpublic void testTransaction(){int rows = accountService.transMoney(1, 2, 100);System.out.println(rows);}
}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...