百度都百度不到jpa多线程的事务回滚,废话少说,就是干,
实现思路(可看可不看,本人也不喜欢罗里吧嗦的,想直接看干货就跳过这里,直接执行代码):
jpa本身是不支持多线程事务,所以要手动实现事务的提交和回滚
,网上可参考的太复杂,而且没用的太多,自己干吧,首先,排除一般的影响事务回滚的条件(jpa事务失效的 场景),事务回滚的前提就是同一个连接,统一提交事务,
但是多线程,是多个实例,都不是同一个连接,自然不能统一回滚了,实现思路:想要实现统一的管理,就要共享同一个事务,同一个connection,我们只能手动管理主线程和子线程,所以要共享EntityManager和EntityTransaction,
需要注意的是不能直接在方法外来初始化EntityManager和EntityTransaction,会报错,通过请求,再获取对象,赋值就可以了
通过内部类,来共享这两个对象,就实现了两个测试的内部类,Thread1和Thread2,
然后通过线程池,来执行多个线程,需要注意的就是,要确定子线程都执行完毕了,再提交事务,不然的话,子线程还在执行,主线程就提交了事务,多线程事务就没法生效
代码都经过测试,直接复制粘贴,代入自己数据源测试就知道了
代码实例
/**
* 注入EntityManager实例
*/
@Autowired
private EntityManagerFactory entityManagerFactory;
//作为多线程的事务共享,从而统一提交或回滚,不能在这里直接createEntityManager和getTransaction
EntityManager entityManager;
EntityTransaction transaction;
//测试方法
@ResponseBody
@RequestMapping(value = "/test")
public RetMsgBean testThread() throws Exception {
//请求的时候给实例和事务赋值
entityManager = entityManagerFactory.createEntityManager();
transaction = entityManager.getTransaction();
try {
//开始事务
transaction.begin();
//执行插入数据操作
Query query = entityManager.createNativeQuery("insert into pt_business_logs(id) value (?)");
//传入参数
query.setParameter(1,"11111");
//提交数据库
query.executeUpdate();
//创建线程池
ExecutorService service= Executors.newFixedThreadPool(10);
//执行事务
service.execute(new Thread1());
//执行事务
service.execute(new Thread2());
//结束线程池
service.shutdown();
/**
* 线程没有结束,就等待500毫秒,可以随意调整等待时间,反正就是要等子线程执行完,
* 不等子线程的话,子线程还在执行,主线程有可能就直接进行commit操作了,多线程事务回滚就无法生效了
*/
while (!service.isTerminated()) {
Thread.sleep(500);
System.out.println("等待子线程执行");
}
//事务执行完成的提示
System.out.println("提交事务");
//提交事务
transaction.commit();
} catch (Exception e) {
//发生异常进行回滚,主线程的回滚不能控制子线程,只是针对主线程的异常
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
System.out.println("发生异常");
}finally {
entityManager.close();
}
//RetMsgBean无所谓,这是一个自定义的返回值类
return RetMsgBean.init();
}
//内部类,线程1,通过继承Runnable实现
class Thread1 implements Runnable{
@Override
public void run() {
try {
//执行数据库操作
Query query = entityManager.createNativeQuery("insert into pt_business_logs(id) value (?)");
query.setParameter(1,"222222");
query.executeUpdate();
//故意抛出异常
System.out.println(1/0);
} catch (Exception e) {
e.printStackTrace();
//进行回滚
transaction.rollback();
}
}
}
//内部类,线程2,通过继承Runnable实现
class Thread2 implements Runnable{
@Override
public void run() {
try {
Query query = entityManager.createNativeQuery("insert into pt_business_logs(id) value (?)");
query.setParameter(1,"333333");
query.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
}
}
}