2013-04-17 32 views
6

tôi nhận được một kết quả điên cuồng lạ với Hibernate (4.1.9.Final) và MySQL (14,14 distrib 5.5.29, InnoDB bảng):Hibernate/MySQL vấn đề đồng thời

Khi tôi kiên trì cái gì đó để sử dụng cơ sở dữ liệu một chủ đề và cố gắng lấy nó bằng cách sử dụng một chủ đề khác, Hibernate không phải lúc nào cũng tìm thấy thực thể.

Một số quan sát (Mặc dù thực tế rằng tôi cam kết đúng cách giao dịch và đóng kiên trì phiên trước khi mở tải phiên.):

  • tôi không có thể tái sản xuất này sử dụng một đơn chương trình đã đọc.

  • tôi thể thấy "mất tích" thực thể trong cơ sở dữ liệu, và

  • Nếu tôi khởi động lại ứng dụng Hibernate thể tải thành công thực thể.

Đây là SSCCE minh họa sự cố. (Các mục nhập bị bỏ qua để ngắn gọn):

public class StressTest { 

    static SessionFactory sessionFactory; 

    public static void main(String[] args) throws InterruptedException, 
                ExecutionException { 

     // Configure Hibernate 
     Configuration conf = new Configuration(); 
     conf.setProperty("hibernate.dialect", 
         "org.hibernate.dialect.MySQLInnoDBDialect"); 
     conf.configure(); 

     ServiceRegistry serviceRegistry = new ServiceRegistryBuilder() 
       .applySettings(conf.getProperties()) 
       .buildServiceRegistry();   

     sessionFactory = conf.buildSessionFactory(serviceRegistry); 

     // Set up producer/consumer 
     BlockingQueue<Long> queue = new LinkedBlockingQueue<Long>(); 

     new Consumer(queue).start(); 
     new Producer(queue).start(); 
    } 

} 

class DummyEntity { 
    long id; 
    public long getId() { return id; } 
    public void setId(long id) { this.id = id; } 
} 

Lớp sản xuất (tạo DummyEntities và vẫn tồn tại).

class Producer extends Thread { 

    BlockingQueue<Long> sink; 

    public Producer(BlockingQueue<Long> sink) { 
     this.sink = sink; 
    } 

    @Override 
    public void run() { 
     try { 
      while (true) { 

       Session session = StressTest.sessionFactory.openSession(); 

       DummyEntity entity = new DummyEntity(); 
       entity.setId(new Random().nextLong()); 

       session.beginTransaction(); 
       session.save(entity); 
       session.getTransaction().commit(); 
       session.close(); 

       sink.put(entity.getId()); 
      } 
     } catch (InterruptedException ignore) { 
      System.exit(-1); 
     } 
    } 
} 

lớp tiêu dùng (tải DummyEntities từ cơ sở dữ liệu):

class Consumer extends Thread { 

    BlockingQueue<Long> source; 

    public Consumer(BlockingQueue<Long> source) { 
     this.source = source; 
    } 

    @Override 
    public void run() { 

     try { 
      while (true) { 

       long entityId = source.take(); 

       Session session = StressTest.sessionFactory.openSession(); 
       Object entity = session.get(DummyEntity.class, entityId); 
       session.close(); 

       if (entity == null) { 
        System.err.printf("Entity with id %d NOT FOUND", entityId); 
        System.exit(-1); 
       } 
      } 
     } catch (InterruptedException ignore) { 
      System.exit(-1); 
     } 
    } 
} 

Cuối cùng, đây là bản đồ-xml cho DummyEntity.

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC 
     "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping 
    default-cascade="all" 
    default-lazy="false"> 

    <class name="se.stresstest.DummyEntity"> 

     <id name="id" type="long"> 
      <generator class="assigned"/> 
     </id> 

    </class> 

</hibernate-mapping> 

Các kết quả đầu ra luôn luôn kết thúc với một cái gì đó như:

Entity with id -225971146115345 NOT FOUND 

ý tưởng Bất kỳ lý do tại sao?

(Đây là một phiên bản tinh tế của một trước question.)

+0

Tôi đã đưa ra câu trả lời cho câu hỏi trước của bạn có thể phù hợp với câu hỏi đó, vui lòng kiểm tra. – didierc

+0

@aioobe những gì về các phiên bản khác của hibernate và/hoặc MySQL – Eugene

+0

@Eugene, tôi không nghĩ rằng đó là một vấn đề Hibernate, và tôi không có các phiên bản MySQL khác trong tầm tay. Nếu tôi thay đổi thành PostgreSQL thì mọi thứ đều hoạt động tốt. – aioobe

Trả lời

0

sử dụng MySQL5InnoDBDialect để thay thế.

+0

Cảm ơn bạn đã đề xuất. Thật không may. : - / – aioobe

1

Hành vi này có thể phù hợp với một chế độ cách ly giao dịch của REPEATABLE READ, mà sẽ xảy ra là mặc định giao dịch chế độ cách ly cho InnoDB:

http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html#isolevel_repeatable-read

Nếu logic ứng dụng của bạn phụ thuộc vào việc có thể để xem dữ liệu cam kết trong các giao dịch khác sau giao dịch hiện tại được bắt đầu - bằng chi phí đọc lặp lại (dữ liệu có thể/sẽ thay đổi do thao tác trong các giao dịch khác) - bạn nên đặt cách ly giao dịch thành READ COMMITTED:

http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html#isolevel_read-committed

Các vấn đề liên quan