jpa多线程事务

百度都百度不到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();
		}
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot提供了许多方便的方法来处理多线事务。以下是一些常用的方法: 1. 声明式事务管理:使用Spring的@Transactional注解来管理事务,可以确保在方法执行过程中,如果出现异常,所有的操作都会回滚到最初的状态。 2. 编程式事务管理:使用Spring的TransactionTemplate来手动管理事务,可以在代码中指定何时开始和提交事务。 3. 分布式事务管理:使用Spring Boot集成的分布式事务管理框架,如Atomikos、Bitronix等,来处理跨多个数据库或消息队列的事务。 无论使用哪种方式,都需要在应用程序中配置数据源、事务管理器和事务通知器等相关组件。可以通过在application.properties文件中设置相关属性来完成配置。例如: spring.datasource.url=jdbc:mysql://localhost/mydb spring.datasource.username=username spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.tomcat.max-active=10 spring.datasource.tomcat.max-idle=5 spring.datasource.tomcat.min-idle=2 spring.datasource.tomcat.test-on-borrow=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.show-sql=true spring.transaction.default-timeout=30 spring.transaction.rollback-on-commit-failure=true 在这个配置文件中,我们定义了数据源、连接池、JPA配置和事务配置等相关属性。这些属性可以根据具体需求进行调整,以达到最佳的性能和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值