Spring Transaction学习笔记--编程式事物声明

一、编程式事物流程

编程式事物实现主要有两种方法,一种是使用TransactionTemplate,另一中就是使用PlatformTransactionManager.这里我主要介绍前者的使用方式。

1、 准备jdbc.properties配置数据库需要的信息,将配置属性注入com.mchange.v2.c3p0.ComboPooledDataSourc,
    得到我们需要的数据源
2、 将DataSource数据源注入到org.springframework.orm.hibernate5.LocalSessionFactoryBean3、 将org.springframework.orm.hibernate5.LocalSessionFactoryBean注入到
    org.springframework.orm.hibernate5.HibernateTransactionManager中,使用Spring管理事务
4、 将org.springframework.orm.hibernate5.HibernateTransactionManager注入到
    org.springframework.transaction.support.TransactionTemplate5、 将org.springframework.orm.hibernate5.LocalSessionFactoryBean注入到DAO层
6、 将org.springframework.transaction.support.TransactionTemplate注入到Service层

两个与事务模板相关的类

TransactionCallBack<T>//如果方法执行没有返回值则覆写此类的方法
TransactionCallBackWithoutResult<T>//如果方法执行有返回值则覆写此类的方法

二、编程式事物例子

Student.java 使用注解的方式实现Object和数据库表的映射

package com.zbt;

import javax.persistence.*;

@Entity
@Table(name="stu")
public class Student {
    @Id
    @Column(name="id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name="first_name")
    private String firstName;
    @Column(name="last_name")
    private String lastName;
    @Column(name="address")
    private String address;
    @Column(name="phone")
    private String phone;
    //省略了getters 和 setters方法

上下文配置文件
第一步 :配置数据源

    <!--使用c3p0配置 使用配置文件的方式需要指明配置文件的位置-->
    <context:property-placeholder location="classpath:/jdbc.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

第二步:使用Spring注入org.springframework.orm.hibernate5.LocalSessionFactoryBean相关属性

<!--使用hibernateProperties + DataSource的方式取代hibernate.cfg.xml文件-->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="annotatedClasses">
            <list>
                <value>com.zbt.Student</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">false</prop>
            </props>
        </property>
    </bean>

第三步: Spring 注入org.springframework.orm.hibernate5.HibernateTransactionManager相关属性

<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

第四步:Spring 注入org.springframework.transaction.support.TransactionTemplate相关属性

<bean id = "transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>//注意这里需要将HibernateTransactionManager注入进来
        <property name="isolationLevelName" value="ISOLATION_READ_COMMITTED"/>//设置隔离级别
        <property name="timeout" value="30"/>//设置事务运行时间
    </bean>

第五步:StudentDao.java 实现与数据库的交互,需要注入SessionFactory

package com.zbt;

import org.hibernate.SessionFactory;

import org.hibernate.query.Query;


public class StudentDao {
    private SessionFactory sessionFactory;
    public void setSessionFactory(SessionFactory sessionFactory){
        this.sessionFactory = sessionFactory;
    }

    public int  saveStudent(Student stu){
        return (int) this.sessionFactory.getCurrentSession().save(stu);
    }

    public void save(Student stu){
        this.sessionFactory.getCurrentSession().save(stu);
    }

    public Integer update(int id,String phone){
        String hql = "update Student set phone =:phone where id = :id";
        Query query = this.sessionFactory.getCurrentSession().createQuery(hql);
        query.setParameter("phone",phone);
        query.setParameter("id",id);
        return query.executeUpdate();
    }
}

上下文中的配置

<bean id="studentDao" class="com.zbt.StudentDao">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

第六步:在StudentService中注入DAO和org.springframework.transaction.support.TransactionTemplate

package com.zbt;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class StudentService {
    private TransactionTemplate transactionTemplate;

    private StudentDao studentDao;

    public void setTransactionTemplate(TransactionTemplate transactionTemplate){
        this.transactionTemplate = transactionTemplate;
    }

    public void setStudentDao(StudentDao studentDao){
        this.studentDao = studentDao;
    }


    public void save(Student stu){
        this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {//方法执行无返回,所以覆盖此类的方法
            @Override
            public void doInTransactionWithoutResult(TransactionStatus status) {
                studentDao.save(stu);
            }
        });
    }

    public Integer update(int id, String phone){
        return this.transactionTemplate.execute(new TransactionCallback<Integer>() {//方法执行有返回,所以覆盖此类的方法
            @Override
            public Integer doInTransaction(TransactionStatus status) {
                try{
                    return studentDao.update(id,phone);
                }catch(Exception e){
                    status.setRollbackOnly();
                }
                return null;
            }
        });
    }
}

最后我们可以看一下全部的上下文配置方案

<?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: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/context
        http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.3.xsd ">

    <!--使用c3p0配置 使用配置文件的方式需要指明配置文件的位置-->
    <context:property-placeholder location="classpath:/jdbc.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--使用hibernateProperties + DataSource的方式取代hibernate.cfg.xml文件-->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="annotatedClasses">
            <list>
                <value>com.zbt.Student</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">false</prop>
            </props>
        </property>
    </bean>
    <!--将事务交给Spring管理-->
    <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <bean id = "transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
        <property name="isolationLevelName" value="ISOLATION_READ_COMMITTED"/>
        <property name="timeout" value="30"/>

    </bean>
        <bean id="studentDao" class="com.zbt.StudentDao">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <bean id="studentService" class="com.zbt.StudentService">
        <property name="transactionTemplate" ref="transactionTemplate"/>
        <property name="studentDao" ref ="studentDao"/>
    </bean>
</beans>

三、TransactionTemplate源码


package org.springframework.transaction.support;


@SuppressWarnings("serial")
public class TransactionTemplate extends DefaultTransactionDefinition
        implements TransactionOperations, InitializingBean {

    /** Logger available to subclasses */
    protected final Log logger = LogFactory.getLog(getClass());

    @Nullable
    private PlatformTransactionManager transactionManager;


    /**
     * Construct a new TransactionTemplate for bean usage.
     * <p>Note: The PlatformTransactionManager needs to be set before
     * any {@code execute} calls.
     * @see #setTransactionManager
     */
    public TransactionTemplate() {
    }

    /**
     * Construct a new TransactionTemplate using the given transaction manager.
     * @param transactionManager the transaction management strategy to be used
     */
    public TransactionTemplate(PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    /**
     * Construct a new TransactionTemplate using the given transaction manager,
     * taking its default settings from the given transaction definition.
     * @param transactionManager the transaction management strategy to be used
     * @param transactionDefinition the transaction definition to copy the
     * default settings from. Local properties can still be set to change values.
     */
    public TransactionTemplate(PlatformTransactionManager transactionManager, 
                                TransactionDefinition transactionDefinition) {
        super(transactionDefinition);
        this.transactionManager = transactionManager;
    }


    /**
     * Set the transaction management strategy to be used.
     */
    public void setTransactionManager(@Nullable PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    /**
     * Return the transaction management strategy to be used.
     */
    @Nullable
    public PlatformTransactionManager getTransactionManager() {
        return this.transactionManager;
    }

    @Override
    public void afterPropertiesSet() {
        if (this.transactionManager == null) {
            throw new IllegalArgumentException("Property 'transactionManager' is required");
        }
    }


    @Override
    @Nullable
    public <T> T execute(TransactionCallback<T> action) throws TransactionException {
        Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

        if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
            return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
        }
        else {
            TransactionStatus status = this.transactionManager.getTransaction(this);
            T result;
            try {
                result = action.doInTransaction(status);
            }
            catch (RuntimeException | Error ex) {
                // Transactional code threw application exception -> rollback
                rollbackOnException(status, ex);
                throw ex;
            }
            catch (Throwable ex) {
                // Transactional code threw unexpected exception -> rollback
                rollbackOnException(status, ex);
                throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
            }
            this.transactionManager.commit(status);
            return result;
        }
    }

    /**
     * Perform a rollback, handling rollback exceptions properly.
     * @param status object representing the transaction
     * @param ex the thrown application exception or error
     * @throws TransactionException in case of a rollback error
     */
    private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
        Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

        logger.debug("Initiating transaction rollback on application exception", ex);
        try {
            this.transactionManager.rollback(status);
        }
        catch (TransactionSystemException ex2) {
            logger.error("Application exception overridden by rollback exception", ex);
            ex2.initApplicationException(ex);
            throw ex2;
        }
        catch (RuntimeException | Error ex2) {
            logger.error("Application exception overridden by rollback exception", ex);
            throw ex2;
        }
    }

猜你喜欢

转载自blog.csdn.net/makeliwei1/article/details/81778847
今日推荐