2015-02-23 17 views
7

Tất cả các phương thức MyService đều được giao dịch. Các thử nghiệm junit dưới đây, được số mục, tiết kiệm một mục mới, và nhận được số mục để đảm bảo rằng số lượng đã được tăng lên bằng cách 1.Spring @transaction không hoạt động như mong đợi ở junit ở chế độ không gỡ lỗi

public class MyTest extends ServiceTest{ 

    1. int countBefore = myService.getCount(); //return n 
    2. myService.add(item);      //item is really added to DB 
    3. int countAfter = myService.getCount(); //return n (sometimes n+1) 
} 

@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED) 
getCount(){…} 

@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.SERIALIZABLE) 
add(){…} 

@Ignore 
@ContextConfiguration(locations = { "file:src/main/resources/xxx-context.xml", 
            "file:src/main/resources/xxx-data.xml", 
            "file:src/main/resources/xxx-services.xml" }) 
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = false) 
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, 
          DirtiesContextTestExecutionListener.class, 
          TransactionalTestExecutionListener.class, 
          TestListener.class}) 

public class ServiceTest extends AbstractUT{ 

@Ignore 
@RunWith(SpringJUnit4ClassRunner.class) 
@TestExecutionListeners({TestListener.class}) 
public class AbstractUT{ 

Khi gỡ lỗi (3.) trả về n + 1 là những gì tôi muốn. Nhưng khi chạy thử nghiệm mà không gỡ lỗi tôi nhận được n.

Thậm chí đôi khi chạy thử nghiệm tôi nhận được n + 1 và lần sau tôi nhận được n và khi so sánh đầu ra std giữa hai lần thực hiện, nó trông giống hệt nhau. Tôi đã kích hoạt log4j.logger.org.springframework.transaction = TRACE và tôi có thể thấy:

Initializing transaction synchronization 
Getting transaction for MyService.getCount 
... 
Completing transaction for MyService.getCount 
Clearing transaction synchronization 

... 

Initializing transaction synchronization 
Getting transaction for MyService.add 
... 
Completing transaction for MyService.add 
Clearing transaction synchronization 

... 

Initializing transaction synchronization 
Getting transaction for MyService.getCount 
... 
Completing transaction for MyService.getCount 
Clearing transaction synchronization 

Vì vậy, giao dịch đang được thực hiện một sau khi khác, nhưng làm thế nào có thể là (3) không thấy mục đã lưu?

giao dịch managment được thiết lập trong lớp học thử nghiệm của tôi theo: https://stackoverflow.com/a/28657650/353985

Làm thế nào tôi có thể tìm thấy những gì đang xảy ra vậy? Cảm ơn!

+0

Bạn có sử dụng '' không? anyway xem câu trả lời của tôi trên [liên kết này] (http://stackoverflow.com/a/25910635/3364187). – Xstian

+0

Hoàn toàn có. – redochka

+0

Bạn có thể thêm cấu hình và TestClass của mình không? – Xstian

Trả lời

3

Có vấn đề tương tự, nhưng trong trường hợp của tôi, nó không khôi phục. Có vẻ như bạn đã quên thêm @Transactional. Từ tài liệu (link)

quản lý giao dịch

Trong khuôn khổ TestContext, giao dịch được quản lý bởi TransactionalTestExecutionListener mà được cấu hình theo mặc định, thậm chí nếu bạn không khai báo rõ ràng @TestExecutionListeners trên của bạn lớp kiểm tra. Để bật hỗ trợ cho giao dịch, tuy nhiên, bạn phải định cấu hình bean PlatformTransactionManager trong ApplicationContext được tải thông qua ngữ nghĩa @ContextConfiguration (chi tiết hơn được cung cấp bên dưới). Ngoài ra, bạn phải khai báo chú thích @Transactional của Spring ở cấp lớp hoặc phương thức cho các bài kiểm tra của bạn.

Dưới đây là ví dụ tạo liên kết ở trên.

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration 
@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false) 
@Transactional 
public class FictitiousTransactionalTest { 

@BeforeTransaction 
public void verifyInitialDatabaseState() { 
    // logic to verify the initial state before a transaction is started 
} 

@Before 
public void setUpTestDataWithinTransaction() { 
    // set up test data within the transaction 
} 

@Test 
// overrides the class-level defaultRollback setting 
@Rollback(true) 
public void modifyDatabaseWithinTransaction() { 
    // logic which uses the test data and modifies database state 
} 

@After 
public void tearDownWithinTransaction() { 
    // execute "tear down" logic within the transaction 
} 

@AfterTransaction 
public void verifyFinalDatabaseState() { 
    // logic to verify the final state after transaction has rolled back 
} 

}

+0

Tôi đã thông báo bạn nói rằng phương pháp của bạn có @Transactional, nhưng tôi vẫn phải thêm chúng vào các cấp độ phương pháp của tôi cho các bài kiểm tra của tôi. – kyla

+0

Thậm chí bằng cách thêm @Transactional vào phương pháp thử nghiệm, tôi nhận được cùng một hành vi. – redochka

+0

tuyên truyền của bạn về giao dịch của bạn là gì? – kyla

0

Một giải pháp tôi đã tìm thấy cho đến bây giờ để vượt qua thử nghiệm là để đưa khẳng định trong phương pháp afterTransaction

public class MyTest kéo dài ServiceTest {

@Test 
public void test(){ 
    1. int countBefore = myService.getCount(); //return n 
    2. myService.add(item);      //item is really added to DB 
} 
 
@AfterTransaction 
public void verifyFinalDatabaseState() { 
    3. int countAfter = myService.getCount(); //
            
 
  
             return n (sometimes n+1)
            
  
                //Now always return n+1 
} 
0

Vì giao dịch đang chạy được đặt tại số test method level, bạn có hai tùy chọn:

  1. Bạn có thể xóa @Transactional khỏi phương pháp thử và dựa vào phương thức dịch vụ của bạn @Transactional đường biên. Bằng cách này, khi bạn gọi:

    int countBefore = myService.getCount(); 
    myService.add(item); 
    int countAfter = myService.getCount(); 
    

Mỗi cuộc gọi dịch vụ này sẽ chạy trong một giao dịch bị cô lập, giống như nó sẽ xảy ra trong cuộc gọi sản xuất thời gian chạy.

  1. Bạn tuôn Hibernate Session, chỉ sau khi thêm mục:

    int countBefore = myService.getCount(); 
    myService.add(item); 
    transactionTemplate.execute(new TransactionCallback<Void>() { 
        @Override 
        public Company doInTransaction(TransactionStatus transactionStatus) { 
         entityManager.flush(); 
         return null; 
        } 
    }); 
    int countAfter = myService.getCount(); 
    

Một HQL truy vấn/đếm JPQL nên kích hoạt một tuôn ra trong chế độ tuôn ra AUTO , nhưng an SQL native query doesn't flush the Session.

+0

Đã thử cả hai tùy chọn câu trả lời của bạn. 1- Bài kiểm tra của tôi không phải là @ giao dịch, 2- Tôi không có entityManager, tôi đang sử dụng sessionFactory.getCurrentSession.flush() Vẫn nhận được cùng một hành vi lạ. Điều duy nhất hoạt động cho đến bây giờ là khẳng định trong @ AfterTransaction. Xem câu trả lời của tôi. – redochka

+0

Bạn cũng có thể sử dụng phiên Hibernate. Hãy thử với 'transactionTemplate' như tôi đã gợi ý. –

0

Tôi đã yêu cầu điều này trong một nhận xét nhưng vì danh tiếng của tôi không cho phép, tôi chỉ cố gắng cung cấp câu trả lời.

Có thể bạn đang sử dụng và ORM lưu trữ kết quả của truy vấn đếm. Tùy thuộc vào cách các phương thức add/getCount của bạn được thực hiện và các cấu hình của ORM và datasource, trong lần gọi thứ hai của getCount, bạn có thể nhận được một giá trị được lưu trữ trong lần gọi đầu tiên của getCount.

Điều này không giải thích được tại sao ở chế độ gỡ lỗi bạn luôn nhận được kết quả chính xác.

+0

Tôi đang sử dụng chế độ ngủ đông và ý tưởng của bạn cũng đến với tôi. Làm thế nào để có được xung quanh bộ nhớ cache hibernate? – redochka

+0

có một cái nhìn ở đây [Cấu hình Hibernate] (https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/session-configuration.html) Bảng 3.5. Tôi tin rằng hibernate.cache.use_query_cache và hibernate.cache.use_second_level_cache sẽ được bạn quan tâm. Hãy thử đặt cả hai thành false trong cấu hình ngủ đông của bạn. –

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