Spring事务配置
首先本文主要讲Spring配置事务的三种方式,目录如下:
一、Xml配置方法
二、Xml和注解配置
三、纯注解配置
首先附上需要的一些Java类:
/*
学生实体类
*/
public class Student implements Serializable {
private Integer id;
private String name;
private Integer age;
private Integer money;
public Student() {
}
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", money=" + money +
'}';
}
}
// 测试类
public class Client {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");//加载配置文件
IStudentService studentService = (IStudentService) ac.getBean("studentService");//获取StudentService的bean对象
Student student = studentService.findStudentById(1);//按照id查找
System.out.println(student);
studentService.transfer("aaa","bbb",100);//转账操作
}
}
需要的jar包:
一、xml配置事务
1. 需要的其他类
/*
操作层实现类:这里用到了JdbcDaoSupport
*/
public class StudentDaoImp extends JdbcDaoSupport implements IStudentDao {
//按照id查找
@Override
public Student fingStudentById(Integer id) {
List<Student> students = getJdbcTemplate().query("select * from stu where id = ?", new BeanPropertyRowMapper<Student>(Student.class), id);
return students.isEmpty()?null: students.get(0);
}
//按照名称查找
@Override
public Student findStudentByName(String name) {
List<Student> students = getJdbcTemplate().query("select * from stu where name = ?", new BeanPropertyRowMapper<Student>(Student.class), name);
if (students.isEmpty()) {
return null;
}
if (students.size() > 1) {
throw new RuntimeException("结果集不唯一,请检查数据");
}
return students.get(0);
}
//更新信息
@Override
public void updateStudent(Student student) {
getJdbcTemplate().update("update stu set money=? where id=?", student.getMoney(), student.getId());
}
}
/*
学生的业务层实现类
*/
public class StudentServiceImp implements IStudentService {
//此处需要用到操作层的接口
private IStudentDao studentDao;
//因为要注入,故必须要有setter()方法
public void setStudentDao(IStudentDao studentDao) {
this.studentDao = studentDao;
}
//按照id查找(注:只是为了演示配置方法,故没有实现所有方法)
@Override
public Student findStudentById(Integer studentId) {
return studentDao.fingStudentById(studentId);
}
@Override
public void transfer(String sourceName, String targetName, Integer money) {
// 1.根据名称查询账户信息
Student source = studentDao.findStudentByName(sourceName);
Student target = studentDao.findStudentByName(targetName);
// 2.转出账户减钱,转入账户加钱
source.setMoney(source.getMoney()-money);
target.setMoney(target.getMoney()+money);
// 3.更新账户信息
studentDao.updateStudent(source);
// int i = 1/0;
studentDao.updateStudent(target);
}
}
2. xml配置文件如下:
<?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:aop="http://www.springframework.org/schema/aop"
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/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 definitions here -->
<!--配置service-->
<bean id="studentService" class="com.renjing.service.imp.StudentServiceImp">
<property name="studentDao" ref="studentDao"></property>
</bean>
<!--配置dao-->
<bean id="studentDao" class="com.renjing.dao.imp.StudentDaoImp">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置Spring内置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/up1"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--Spring基于xml的声明式事务控制-->
<!--第一步:配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--第二步:配置事务的通知:tx:advice标签-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--配置事务的属性:tx:attributes标签
isolation:配置事务的隔离级别。默认值:DEFAULT,使用数据库的默认隔离级别。mysql是repeatable-read。
propagation:配置事务的传播行为。默认值是:REQUIRED。一般的选择(增删改方法)。当是查询方法时,选择SUPPORTS。
timeout:指定事务的超时时间。默认值是:-1。永不超时。当指定其他值时,以秒为单位。
read-only:配置是否只读事务。默认值是:false,读写型事务。当指定为true时,表示只读事务,只能用于查询方法。
rollback-for:用于指定一个异常,当产生该异常时,事务回滚。产生其他异常时,事务不回滚。没有默认值,任何异常都回滚。
no-rollback-for:用于指定一个异常,当执行产生该异常时,事务不回滚。产生其他异常时,事务回滚。没有默认值,任何异常都回滚。
-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"></tx:method><!--增删改-->
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
<!--第三步:配置aop
要配的是:切入点表达式以及事务通知和切入点表达式的关联
-->
<aop:config>
<!--配置切入点表达式-->
<aop:pointcut id="pt1" expression="execution(* com.renjing.service.imp.*.*(..))"></aop:pointcut>
<!--配置事务通知和切入点表达式的关联-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>
</beans>
二、xml和注解配置
1. 需要改变的一些类
/*
业务层实现类
*/
@Service("studentService")//注入studentService
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)//配置读写型事务
//@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)//只读型,不能控制增删改的事务
public class StudentServiceImp implements IStudentService {
//自动装配
@Autowired
private IStudentDao studentDao;
@Override
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)//将查找配置为只读型事务,效率会更高一些
public Student findStudentById(Integer studentId) {
return studentDao.fingStudentById(studentId);
}
@Override
public void transfer(String sourceName, String targetName, Integer money) {
// 1.根据名称查询账户信息
Student source = studentDao.findStudentByName(sourceName);
Student target = studentDao.findStudentByName(targetName);
// 2.转出账户减钱,转入账户加钱
source.setMoney(source.getMoney()-money);
target.setMoney(target.getMoney()+money);
// 3.更新账户信息
studentDao.updateStudent(source);
// int i = 1/0;
studentDao.updateStudent(target);
}
}
/*
操作层实现类
*/
@Repository("studentDao")
public class StudentDaoImp implements IStudentDao {
//自动装配
@Autowired
private JdbcTemplate jdbcTemplate;
//按照id查找
@Override
public Student fingStudentById(Integer id) {
List<Student> students = jdbcTemplate.query("select * from stu where id = ?", new BeanPropertyRowMapper<Student>(Student.class), id);
return students.isEmpty()?null: students.get(0);
}
@Override
public Student findStudentByName(String name) {
List<Student> students = jdbcTemplate.query("select * from stu where name = ?", new BeanPropertyRowMapper<Student>(Student.class), name);
if (students.isEmpty()) {
return null;
}
if (students.size() > 1) {
throw new RuntimeException("结果集不唯一,请检查数据");
}
return students.get(0);
}
@Override
public void updateStudent(Student student) {
jdbcTemplate.update("update stu set money=? where id=?", student.getMoney(), student.getId());
}
}
2. xml配置文件如下
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
<!--配置spring创建容器时要扫描的包-->
<context:component-scan base-package="com.renjing"></context:component-scan>
<!--配置jdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置Spring内置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/up1"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--Spring基于xml和注解组合的配置步骤-->
<!--第一步:配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--第二步:配置Spring开启注解事务的支持-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<!--在需要事务的地方使用@Transactional注解
该注解可以写在接口上,类上和方法上
写在接口上,表示该接口的所有实现类都有事务。
写在类上,表示该类中的所有方法都有事务。
写在方法上,表示该方法有事务。
优先级:就近原则。
-->
</beans>
三、纯注解配置
1. 需要改变的一些类
/*
操作层实现类
*/
@Repository("studentDao")//注入操作层实现类
public class StudentDaoImp implements IStudentDao {
//自动装配
@Autowired
private JdbcTemplate jdbcTemplate;
//按照id查找
@Override
public Student fingStudentById(Integer id) {
List<Student> students = jdbcTemplate.query("select * from stu where id = ?", new BeanPropertyRowMapper<Student>(Student.class), id);
return students.isEmpty()?null: students.get(0);
}
//按照名称查找
@Override
public Student findStudentByName(String name) {
List<Student> students = jdbcTemplate.query("select * from stu where name = ?", new BeanPropertyRowMapper<Student>(Student.class), name);
if (students.isEmpty()) {
return null;
}
if (students.size() > 1) {
throw new RuntimeException("结果集不唯一,请检查数据");
}
return students.get(0);
}
//更新信息
@Override
public void updateStudent(Student student) {
jdbcTemplate.update("update stu set money=? where id=?", student.getMoney(), student.getId());
}
}
/*
业务层实现类
*/
@Service("studentService")//注入业务层实现类
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)//配置事务,读写型
//@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)//只读型,不能控制增删改的事务
public class StudentServiceImp implements IStudentService {
//自动装配
@Autowired
private IStudentDao studentDao;
@Override
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)//配置只读型事务,对于查找来说,效率要高一些
public Student findStudentById(Integer studentId) {
return studentDao.fingStudentById(studentId);
}
//转账操作
@Override
public void transfer(String sourceName, String targetName, Integer money) {
// 1.根据名称查询账户信息
Student source = studentDao.findStudentByName(sourceName);
Student target = studentDao.findStudentByName(targetName);
// 2.转出账户减钱,转入账户加钱
source.setMoney(source.getMoney()-money);
target.setMoney(target.getMoney()+money);
// 3.更新账户信息
studentDao.updateStudent(source);
int i = 1/0;
studentDao.updateStudent(target);
}
}
2. 新增的配置类
/*
事务控制的配置类
*/
public class TransactionManager {
@Bean(name = "transactionManager")//配置事务管理器
public PlatformTransactionManager createTransactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
/*
连接数据库的配置类
*/
public class JdbcConfig {
@Bean(name = "jdbcTemplate")//将jdbcTemplate注入容器
public JdbcTemplate createJdbcTeplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
@Bean(name = "dataSource")//将数据源dataSource注入容器
public DataSource createDataSource(){
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/up1");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
/*
Spring的配置类,作用就是当bean.xml用
*/
@Configuration//声明为配置类
@ComponentScan("com.renjing")//要扫描的包
@Import({JdbcConfig.class,TransactionManager.class})//导入其他配置类
@EnableTransactionManagement//配置开启Spring注解事务的支持
public class SpringConfiguration {
}
以上就是Spring事务的三种配置方式。
如有问题,欢迎指正~