我正在使用struts2 - spring 3.2.2和mybatis。
首先,我的要求是:
制作一个交易管理实用程序,其中
按照要求,我创建了简单的程序。 我的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;
}
}
//接口: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;
}
//将在其中执行所有与数据库相关的操作的实用程序类 //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;
}
}
现在,当我运行程序时......输出是这样的:
插入之前 .................交易活着? .....假
插入..................交易活着? ....真
插入................交易活着? ......假
部门信息
部门ID:1
部门名称:si
部门编号:251
部门名称:esb
部门ID:293
部门名称:esb
Emp Info
Emp ID:1
部门ID:1
Emp名称:s
更新.................交易活着? .....真
java.lang.RuntimeException:模拟错误情况
更新后.................交易活着? .....假
部门信息
部门ID:1
部门名称:si
部门编号:251
部门名称:esb
部门ID:293
部门名称:esb
Emp Info
Emp ID:1
部门ID:1
Emp名称: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都在其他包装中,我是从春天注入的。
然后诀窍也没有用。
看输出:
在插入部门之前是真的
Deptartment
部门ID:1
部门名称:si
部门ID:2
部门名称:esb
部门ID:3
员工
Emp Id:1
Emp名称:kkkkk
输入部门号码
4
输入部门名称
ASDWE
插入部门后
Deptartment
部门ID:1
部门名称:si
部门ID:2
部门名称:esb
部门ID:3
部门名称:esb
部门ID:4
部门名称:asdwe
- 此处发生例外 org.springframework.dao.DataIntegrityViolationException:
更新后Emp
Deptartment
部门ID:1
部门名称:si
部门ID:2
部门名称:esb
部门ID:3
部门名称:esb
部门ID:4
部门名称:asdwe
... 看这里,之前插入的部门,这里没有回滚...... (我们可以在这里使用sqlSessionTemplate的回滚方法,但是弹簧自动事务管理的用途是什么?我相信这样做是没有意义的!) 问题是什么,我真的没得到......
Plz提供了一些有效的解决方案......
答案 0 :(得分:3)
第一个事务,已插入行的事务已经过了很长时间,并且在更新时抛出异常时会提交。你可能想要实现的是在StartTransAction.execute
中的try / catch中作为单个事务运行整个块。
一般情况下,不建议在dao级别定义事务 - 而MyUpdateUtil
看起来像是带有select / insert / update方法的dao对象。您应该管理服务层中的事务。
首先,将这些行移至MyUpdateUtil
中的新方法:
@Transactional
public void insertAndUpdate(Department dept) {
this.insert(dept);
this.select();
this.update(true);
}
然后从execute
try / catch块调用它。这将为您提供进一步代码抛光的工作起点。