gpt4 book ai didi

spring - 使用@Transactional : transaction get commited even if exception thrown

转载 作者:行者123 更新时间:2023-12-04 05:07:04 26 4
gpt4 key购买 nike

我正在使用 struts2 - spring 3.2.2 和 mybatis。

首先我的要求是:

制作一个事务管理实用程序,其中

  • 如果在当前事务的其他语句中抛出任何异常,则必须回滚事务。 (其他 db 操作可以通过不同的类执行,即不在同一个类中。)

  • 按照要求,我创建了简单的程序。
    我的 applicationContext.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">

    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- Initialization for data source -->
    <bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
    <property name="url" value="jdbc:sqlserver://localhost;database=master;integratedSecurity=true;"/>
    <property name="username" value="Jaydeep"/>
    <property name="password" value="Acty#System123"/>
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />

    <property name='mapperLocations' value='classpath*:test/xml/*.xml' />
    </bean>

    <bean class='org.mybatis.spring.mapper.MapperScannerConfigurer'>
    <property name='basePackage' value='test.dao' />
    </bean>

    <bean id='sqlSession' class='org.mybatis.spring.SqlSessionTemplate'>
    <constructor-arg index='0' ref='sqlSessionFactory' />
    </bean>

    <bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="serviceProvider"
    class="DataServiceProvider">
    <property name="sqlSession" ref="sqlSession" />
    </bean>

    <bean id="updutil" class="MyUpdateUtil">
    <property name="serviceProvider" ref="serviceProvider"></property>
    </bean>

    </beans>

    //DataServiceProvider.java
    import org.apache.ibatis.session.SqlSession;
    import test.dao.DepartmentMapper;
    import test.dao.EmployeeMapper;

    public class DataServiceProvider {
    private SqlSession sqlSession;
    public DepartmentMapper getDeptMapper() {
    if(sqlSession != null)
    return sqlSession.getMapper(DepartmentMapper.class);
    else
    System.out.println("session null");
    return null;
    }
    public EmployeeMapper getEmpMapper() {
    if(sqlSession != null)
    return sqlSession.getMapper(EmployeeMapper.class);
    else
    System.out.println("session null");
    return null;
    }

    public SqlSession getSqlSession() {
    return sqlSession;
    }

    public void setSqlSession(SqlSession sqlSession) {
    this.sqlSession = sqlSession;
    }
    }

    //接口(interface):fooService.java
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import org.springframework.transaction.annotation.Transactional;
    import test.model.Department;

    @Transactional
    public interface fooService {

    public void update(boolean isThrow) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException;

    public void insert(Department dept) throws IOException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException;

    public void select() throws IOException;
    }

    //将在其中执行所有db相关操作的实用程序类
    //MyUpdateUtil.java
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.math.BigDecimal;
    import java.util.List;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.transaction.annotation.Transactional;
    import test.model.Department;
    import test.model.Employee;
    import test.model.EmployeeExample;

    @Transactional
    public class MyUpdateUtil implements fooService {

    public void update(boolean isThrow) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException {
    System.out.println("Updating...................Transaction alive? ..." + StartTransAction.isActive());
    if(isThrow)
    throw new RuntimeException("simulate Error condition") ;
    Employee record = new Employee();
    EmployeeExample example = new EmployeeExample();
    example.createCriteria().andDeptidEqualTo(1L);

    record.setEmpid(1L);
    record.setDeptid(1L);
    record.setEmpname("jaydeep");
    record.setSalary(BigDecimal.valueOf(2000));

    getServiceProvider().getEmpMapper().updateByExampleWithBLOBs(record, example);
    }
    @Transactional
    public void insert(Department dept) throws IOException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
    System.out.println("Inserting....................Transaction alive? .." + StartTransAction.isActive());
    getServiceProvider().getDeptMapper().insert(dept);
    }

    public void select() throws IOException {
    System.out.println("Dept Info");
    List<Department> deptList = getServiceProvider().getDeptMapper().selectByExampleWithBLOBs(null);
    for(Department d : deptList) {
    System.out.println("Dept ID: " + d.getDeptid());
    System.out.println("Dept Name: " + d.getDeptname());
    }
    System.out.println("Emp Info");
    List<Employee> empList = getServiceProvider().getEmpMapper().selectByExampleWithBLOBs(null);
    for(Employee e : empList) {
    System.out.println("Emp ID: " + e.getEmpid());
    System.out.println("Dept ID: " + e.getDeptid());
    System.out.println("Emp Name: " + e.getEmpname());
    }
    }
    @Autowired(required=true)
    private DataServiceProvider serviceProvider;
    public DataServiceProvider getServiceProvider() {
    return serviceProvider;
    }

    public void setServiceProvider(DataServiceProvider serviceProvider) {
    this.serviceProvider = serviceProvider;
    }
    }

    //以及当我单击jsp页面中的链接时执行的主要操作......
    //StartTransAction.java
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.util.Random;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import test.model.Department;

    import com.opensymphony.xwork2.ActionSupport;


    public class StartTransAction extends ActionSupport {
    private static final long serialVersionUID = 1L;

    public String execute() throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException {
    Department dept = new Department();
    dept.setDeptid(Long.valueOf(String.valueOf(new Random().nextInt(500))));
    dept.setDeptname("esb");
    System.out.println("before Insert..................Transaction alive? ...." + isActive());
    try {
    updutil.insert(dept);

    System.out.println("After Insert..................Transaction alive? ...." + isActive());
    updutil.select();
    updutil.update(true);
    } catch (Exception e) {
    System.out.println(e.toString());
    }finally{
    System.out.println("After Update.................Transaction alive? ....." + isActive());
    updutil.select();
    }
    return SUCCESS;
    }
    @Autowired
    fooService updutil;

    public fooService getUpdutil() {
    return new MyUpdateUtil();
    }
    public void setUpdutil(fooService updutil) {
    this.updutil = updutil;
    }
    private DataSourceTransactionManager transactionManager;

    public DataSourceTransactionManager getTransactionManager() {
    return transactionManager;
    }
    public void setTransactionManager(
    DataSourceTransactionManager transactionManager) {
    this.transactionManager = transactionManager;
    }

    public static boolean isActive() throws IOException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    Class tsmClass = contextClassLoader.loadClass("org.springframework.transaction.support.TransactionSynchronizationManager");
    Boolean isActive = (Boolean) tsmClass.getMethod("isActualTransactionActive", null).invoke(null, null);
    return isActive;
    }
    }

    现在当我运行程序时......输出是这样的:

    在插入之前............事务还活着吗? .....错误的
    插入...........事务还活着? ....真的
    插入后......事务还活着? ......错误的
    部门信息
    部门编号:1
    部门名称:si
    部门编号:251
    部门名称:esb
    部门编号:293
    部门名称:esb

    企业信息
    员工编号:1
    部门编号:1
    企业名称:s
    更新中........事务还活着? .....真的
    java.lang.RuntimeException:模拟错误情况
    更新后........事务还活着? .....错误的
    部门信息
    部门编号:1
    部门名称:si
    部门编号:251
    部门名称:esb
    部门编号:293
    部门名称:esb

    企业信息
    员工编号:1
    部门编号:1
    企业名称:s

    较粗的部分是插入的新记录。

    抛出运行时异常后,我需要插入的记录必须回滚。但如输出所示,即使抛出异常,记录也会被提交。
    正如我们所见,事务也在 update() 方法中继续进行。

    请帮助我实现这一目标。我尝试了很多,但没有工作。
    如果可能的话,给我上述问题的工作代码....

    编辑:
    我完全替换了上面的代码。

    现在我有以下文件:

    //applicationContext.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">

    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- bean id="serviceProvider" class="DataServiceProvider"></bean-->
    <!-- Initialization for data source -->
    <bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
    <property name="url" value="jdbc:sqlserver://localhost;database=master;integratedSecurity=true;"/>
    <property name="username" value="Jaydeep"/>
    <property name="password" value="Acty#System123"/>

    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name='mapperLocations' value='classpath*:test/xml/*.xml' />
    </bean>

    <bean class='org.mybatis.spring.mapper.MapperScannerConfigurer'>
    <property name='basePackage' value='test.dao' />
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>


    <bean id='sqlSession' class='org.mybatis.spring.SqlSessionTemplate'>
    <constructor-arg index='0' ref='sqlSessionFactory' />
    </bean>

    <bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
    <property name="nestedTransactionAllowed" value="true" />
    <property name="validateExistingTransaction" value="true" />
    </bean>

    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index='0' ref='sqlSessionFactory' />
    </bean>

    <bean id="myService" class="service.MyService">
    <property name="sqlSessionTemplate" ref="sqlSessionTemplate" />
    </bean>
    </beans>

    //StartTransAction.java
    package com.acty;
    import java.lang.reflect.InvocationTargetException;
    import service.MyService;

    import com.opensymphony.xwork2.ActionSupport;

    public class StartTransAction extends ActionSupport {
    private static final long serialVersionUID = 1L;

    public String execute(){
    myService.startOperations();
    return SUCCESS;
    }

    public static boolean isActive() {
    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    Class tsmClass = null;
    try {
    tsmClass = contextClassLoader.loadClass("org.springframework.transaction.support.TransactionSynchronizationManager");
    } catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    Boolean isActive = null;
    try {
    isActive = (Boolean) tsmClass.getMethod("isActualTransactionActive", null).invoke(null, null);
    } catch (IllegalAccessException | IllegalArgumentException
    | InvocationTargetException | NoSuchMethodException
    | SecurityException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    return isActive;
    }

    private MyService myService;

    public void setMyService(MyService myService) {
    this.myService = myService;
    }
    }

    和//MyService.java
    package service;

    import java.util.List;
    import java.util.Scanner;

    import org.mybatis.spring.SqlSessionTemplate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;

    import test.dao.DepartmentMapper;
    import test.dao.EmployeeMapper;
    import test.model.Department;
    import test.model.Employee;
    import test.model.EmployeeExample;

    @Service
    @EnableTransactionManagement
    @Transactional(propagation=Propagation.REQUIRED)
    public class MyService {
    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
    this.sqlSessionTemplate = sqlSessionTemplate;
    }
    @Transactional(propagation=Propagation.REQUIRED)
    public void startOperations() {
    DepartmentMapper deptMapper = sqlSessionTemplate.getMapper(DepartmentMapper.class);
    EmployeeMapper empMapper = sqlSessionTemplate.getMapper(EmployeeMapper.class);

    System.out.println("Before Insert Dept" + com.acty.StartTransAction.isActive());

    this.select(deptMapper, empMapper);

    Department dept = new Department();
    //insert new dept
    Scanner sc = new Scanner(System.in);
    System.out.println("Enter dept id ");
    dept.setDeptid(sc.nextLong());
    System.out.println("Enter dept Name ");
    dept.setDeptname(sc.next());

    deptMapper.insert(dept);

    System.out.println("After Insert Dept" + com.acty.StartTransAction.isActive());

    this.select(deptMapper, empMapper);

    this.select(deptMapper, empMapper);
    //now update employee

    EmployeeExample example = new EmployeeExample();
    example.createCriteria().andEmpidEqualTo(1L);

    Employee emp = new Employee();
    emp.setEmpname("jjj");

    try {
    //empMapper.updateByExampleSelective(emp, example);
    empMapper.updateByExampleWithBLOBs(emp, example);
    }catch(Exception e) {
    e.printStackTrace();
    }
    System.out.println("After Update Emp");

    this.select(deptMapper, empMapper);
    }
    public void select(DepartmentMapper deptMapper, EmployeeMapper empMapper) {
    System.out.println("\nDeptartment\n");
    List<Department> deptList= deptMapper.selectByExampleWithBLOBs(null);
    for(Department de : deptList) {
    System.out.println(" Dept Id : " + de.getDeptid());
    System.out.println(" Dept Name : " + de.getDeptname());
    }
    System.out.println("\nEmployee\n");
    List<Employee> empList= empMapper.selectByExampleWithBLOBs(null);
    for(Employee emp : empList) {
    System.out.println(" Emp Id : " + emp.getEmpid());
    System.out.println(" Emp Name : " + emp.getEmpname());
    }
    }
    }

    //现在我在服务层做事。
    所有 DAO 都在其他包中,我是从 spring 注入(inject)的。

    然后这个技巧也不起作用。
    查看输出:
    插入部门之前为真

    部门

    部门编号:1
    部门名称:si
    部门编号:2
    部门名称:esb
    部门编号:3

    员工

    员工编号:1
    企业名称 : kkkkk
    输入部门编号
    4
    输入部门名称
    asdwe
    插入部门后

    部门

    部门编号:1
    部门名称:si
    部门编号:2
    部门名称:esb
    部门编号:3
    部门名称:esb
    部门编号:4
    部门名称:asdwe

    -- 这里发生异常
    org.springframework.dao.DataIntegrityViolationException:

    更新数据库时出错。原因:com.microsoft.sqlserver.jdbc.SQLServerException: Ca

    ......

    更新后 Emp
    部门

    部门编号:1
    部门名称:si
    部门编号:2
    部门名称:esb
    部门编号:3
    部门名称:esb
    部门编号:4
    部门名称:asdwe

    ...
    看这里,之前插入的部门,这里没有回滚.....
    (这里我们可以对sqlSessionTemplate使用回滚的方法,但是那么spring自动事务管理有什么用呢?这样做是没有意义的,我相信!)
    什么问题,我真的没搞懂...

    请提供一些工作解决方案...

    最佳答案

    当您在更新中抛出异常时,第一个事务(插入您的行)早已结束并提交。您可能想要实现的是在 StartTransAction.execute 中的 try/catch 中运行整个 block 。作为单一交易。

    一般来说,不建议在 dao 级别定义事务 - 以及您的 MyUpdateUtil看起来像一个带有选择/插入/更新方法的 dao 对象。您应该在服务层管理事务。

    首先,将这些行移到 MyUpdateUtil 中的新方法中。 :

    @Transactional
    public void insertAndUpdate(Department dept) {
    this.insert(dept);
    this.select();
    this.update(true);
    }

    然后调用 execute尝试/捕获 block 。这将为您提供进一步完善代码的工作起点。

    关于spring - 使用@Transactional : transaction get commited even if exception thrown,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15404378/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com