您现在的位置是:首页 > 正文

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

2024-01-30 23:21:41阅读 0

一、编程式事物流程

编程式事物实现主要有两种方法,一种是使用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;
        }
    }

网站文章

  • 微软手机停止服务器,黯然退场!微软手机操作系统停更 比尔·盖茨多次痛惜错过机会...

    微软手机停止服务器,黯然退场!微软手机操作系统停更 比尔·盖茨多次痛惜错过机会...

    图为无关微软的移动操作系统停更了。微软正式宣布,12月10日起,将停止对Windows 10 Mobile最新版本的支持。Windows phone仍然可以运行,但运行最后官方支持的Windows 1...

    2024-01-30 23:21:11
  • 进制转换(java实现)

    405. 数字转换为十六进制数 StringBuilder 要求返回字符串,使用StringBuilder。StringBuilder是线程不安全的,但是相对于StringBuffer速度较快,虽然S...

    2024-01-30 23:21:04
  • 判断一棵树是否为平衡二叉树

    平衡二叉树即为树中任意节点的左右两子树高度差不超过1struct TreeNode{ int val; TreeNode* left; TreeNode* right; TreeNode(int a) :val(a), left(NULL), right(NULL) {};};struct rType { bool isBalanced; int height; rType...

    2024-01-30 23:20:57
  • C++ QT CRC16校验 函数封装 最新发布

    CRC16 C++ QT QString的校验方式

    2024-01-30 23:20:28
  • Typescript学习(二):编译选项

    Typescript学习(二):编译选项

    这个strict相关标志位的一个总开关, 设置为true会启用全部compilerOptions.strict开头的选项和其他相关的选项, 如compilerOptions.strictNullChe...

    2024-01-30 23:20:21
  • 【项目原理】DRM驱动概念、组成、框架、源码分析

    【项目原理】DRM驱动概念、组成、框架、源码分析

    Linux 中的驱动和驱动是两种不同的图形驱动方式,它们之间有一些区别。DRM驱动:总之,一句话,DRM是Linux目前主流的图形显示框架,相比FB架构,DRM更能适应当前日益更新的显示硬件。

    2024-01-30 23:20:14
  • LInux——五种IO模型

    LInux——五种IO模型

    Linux中的IO简述IO主要分为以下的三种:内存IO网络IO磁盘IO通常我们所说的IO是后两者,Linux中无法直接操作IO设备,必须通过系统调用请求kernal来协助完成IO的动作,内存会为每一个...

    2024-01-30 23:20:06
  • PageHelper 分页查询「实现篇」

    两种情况分两种情况:查出来为 PageQueryRespDTO查出来直接是 Model查出来为 PageQueryRespDTOpublic PageInfo<PageQueryRespDTO> qu...

    2024-01-30 23:19:36
  • 洛谷题目目录 热门推荐

    #1 新手村 关卡1-1 洛谷的第一个任务 超级玛丽游戏(洛谷-P1000):点击这里 A+B Problem(洛谷-P1001):点击这里 小玉买文具(洛谷-P1421):点击这里 小鱼的游泳时间(...

    2024-01-30 23:19:28
  • mysql数据丢失_MySQL是如何保证数据的完整性

    mysql数据丢失_MySQL是如何保证数据的完整性

    本文内容主要介绍了MySQL是如何保证数据的完整性,帮助大家更好的理解和学习MySQL,感兴趣的朋友可以了解下!!!数据的一致性和完整性对于在线业务的重要性不言而喻,如何保证数据不丢呢?今天我们就探讨下关于数据的完整性和强一致性,MySQL做了哪些改进。一. MySQL的二阶段提交 在Oracle和MySQL这种关系型数据库中,讲究日志先行策略(Write-Ahead Logging),只要...

    2024-01-30 23:19:20