【问题标题】:Java: Running transaction in multithreaded environmentJava:在多线程环境中运行事务
【发布时间】:2014-02-26 03:07:40
【问题描述】:

我们正在推出一个在短时间内会产生大量流量的网站。基本上就是给票。代码是用 Java、Spring 和 Hibernate 编写的。我想通过产生多个线程并尝试使用 JUnit 测试用例来获取票证来模拟高容量。问题是在我的 DAO 类中,代码只是在我开始事务后就死掉了。我的意思是日志文件中没有错误跟踪或类似的东西。让我对我的代码的方式提出一些想法。

DAO 代码:

@Repository("customerTicketDAO")
public class CustomerTicketDAO extends BaseDAOImpl {// BaseDAOImpl extends HibernateDaoSupport

public void saveCustomerTicketUsingJDBC(String customerId) {
  try{
      getSession().getTransaction().begin(); //NOTHING HAPPENS AFTER THIS LINE OF CODE
      // A select query
      Query query1 = getSession().createSQLQuery("my query omitted on purpose");
      .
      .
      // An update query
      Query query2 = getSession().createSQLQuery("my query omitted on purpose");
      getSession().getTransaction().commite();
   } catch (Exception e) {
   }
}

可运行代码:

public class InsertCustomerTicketRunnable implements Runnable {

@Autowired
private CustomerTicketDAO customerTicketDAO;    

 public InsertCustomerTicketRunnable(String customerId) {
    this.customerId = customerId;
}     

 @Override
public void run() {
    if (customerTicketDAO != null) {
        customerTicketDAO.saveCustomerTicketUsingJDBC(customerId); 
    }
}
}

JUnit 方法:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"file:src/test/resources/applicationContext-test.xml"})
public class DatabaseTest {
  @Before
public void init() {
    sessionFactory = (SessionFactory)applicationContext.getBean("sessionFactory");
    Session session = SessionFactoryUtils.getSession(sessionFactory, true);
    TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));

    customerTicketDAO = (CustomerTicketDAO)applicationContext.getBean("customerTicketDAO");
}

@After
public void end() throws Exception {
    SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
    SessionFactoryUtils.closeSession(session);
  }

  @Test
public void saveCustomerTicketInMultipleThreads () throws Exception  {
    ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);

    for (int i=0; i<1000; i++) {
        executor.submit(new InsertCustomerTicketRunnable(i));
    }

    // This will make the executor accept no new threads
    // and finish all existing threads in the queue
    executor.shutdown();
    // Wait until all threads are finish
    executor.awaitTermination(1, TimeUnit.SECONDS);
}

我看到没有数据被插入到数据库中。有人可以指出我哪里出错了吗?

谢谢 拉杰

【问题讨论】:

    标签: multithreading spring hibernate junit executorservice


    【解决方案1】:

    SessionFactory 是线程安全的,但 Session 不是。所以我的猜测是你需要从每个线程中调用SessionFactoryUtils.getSession(),以便每个线程都有自己的实例。您当前正在从主线程调用它,因此所有子线程都尝试共享同一个实例。

    【讨论】:

    • 我一定会尝试您的建议并让您知道。谢谢你的建议。
    • 就是这样。我已将您的回复标记为对问题的回答。非常感谢大卫。
    【解决方案2】:

    淘气,淘气!

    public void saveCustomerTicketUsingJDBC(String customerId) {
      try {
          getSession().getTransaction().begin(); //NOTHING HAPPENS AFTER THIS LINE OF CODE
          .
          .
       } catch (Exception e) {
       }
    }
    

    您永远不应该(嗯,几乎永远不会)有一个空的catch 块,如果出现问题,您会发现您的代码“只是简单地死掉”而没有日志消息。哦,看,这就是正在发生的事情;)

    您至少应该记录异常,这将大大有助于您找到问题所在(并从那里找到解决方案)。

    【讨论】:

    • 为了简洁起见,我省略了那段代码。我在异常块中有一个记录器。
    猜你喜欢
    • 1970-01-01
    • 2012-06-26
    • 2018-02-23
    • 1970-01-01
    • 1970-01-01
    • 2020-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多