CyclicBarrier
加入数据库连接够用的前提下:
@Autowired
private PlatformTransactionManager platformTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
private void thread1(AtomicBoolean rollback, CyclicBarrier cb) {
TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager);
transactionTemplate.execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus transactionStatus) {
try {
contentService.updateById(new Content().setId(2L).setSort(1));
} catch (Exception e) {
rollback.set(true);
}
try {
cb.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
if (rollback.get()) {
transactionStatus.setRollbackOnly();
}
return null;
}
});
}
private void thread2(AtomicBoolean rollback, CyclicBarrier cb) {
TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
try {
contentService.updateById(new Content().setId(1L).setSort(1));
} catch (Exception e) {
rollback.set(true);
}
try {
cb.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
if (rollback.get()) {
platformTransactionManager.rollback(transaction);
return;
}
platformTransactionManager.commit(transaction);
}
@Override
@Transactional
public void test(String s) throws SQLException {
AtomicBoolean rollback = new AtomicBoolean(false);
CyclicBarrier cb = new CyclicBarrier(3);
new Thread(new Runnable() {
@Override
public void run() {
thread1(rollback, cb);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
thread2(rollback, cb);
}
}).start();
try {
cb.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
if (rollback.get()) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
缺点:一个线程一个事务,一个连接,可能把连接池耗空。
多个线程对应多个事务,如果操作同一张表有可能死锁。
可考虑分布式事务。
CountDownLatch 可以由CyclicBarrier改造
mybatis 版
@Resource
private SqlSessionTemplate sqlSessionTemplate;
public void test(String s) throws SQLException {
SqlSessionFactory sqlSessionFactory = sqlSessionTemplate.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
Connection connection = sqlSession.getConnection();
connection.setAutoCommit(false);
ContentDao mapper = sqlSession.getMapper(ContentDao.class);
Content c = new Content().setTime(LocalDateTime.now()).setUrl("test3").setPic("pic3").setCategoryId(0).setSort(0);
mapper.insert(c);
AtomicBoolean rollFlag = new AtomicBoolean(false);
CompletableFuture<Void> job1 = CompletableFuture.runAsync(() -> {
Content content = mapper.selectById(1);
content.setSort(10);
mapper.updateById(content);
}).exceptionally(e -> {
e.printStackTrace();
rollFlag.set(true);
return null;
});
CompletableFuture<Void> job2 = CompletableFuture.runAsync(() -> {
Content content = mapper.selectById(2);
content.setSort(10);
mapper.updateById(content);
int a = 1 / 0;
}).exceptionally(e -> {
e.printStackTrace();
rollFlag.set(true);
return null;
});
try {
CompletableFuture.allOf(job1, job2).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
rollFlag.set(true);
} finally {
if (rollFlag.get()) {
connection.rollback();
} else {
connection.commit();
}
connection.close();
}
}
jpa 版
Connection connection = session.doReturningWork(new AbstractReturningWork<Connection>() {
@Override
public Connection execute(Connection connection) throws SQLException {
connection.setAutoCommit(false);
return connection; //获取原生jdbc操作
}
});
public void test2(Integer a) throws SQLException {
EntityManager entityManager = entityManagerFactory.createEntityManager();
Session session = entityManager.unwrap(Session.class);
AtomicBoolean rollFlag = new AtomicBoolean(false);
Transaction transaction = session.beginTransaction();
CompletableFuture<Void> job1 = CompletableFuture.runAsync(() -> {
Customer customer = session.get(Customer.class, 1L);
customer.setAge(10);
session.save(customer);
}).exceptionally(e -> {
e.printStackTrace();
rollFlag.set(true);
return null;
});
try {
CompletableFuture.allOf(job1).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
rollFlag.set(true);
} finally {
if (rollFlag.get()) {
transaction.rollback();
} else {
transaction.commit();
}
}
}