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包:
【Spring】Spring事务配置

一、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事务的三种配置方式。
如有问题,欢迎指正~

相关文章: