2014-10-28 11 views
16

Tôi có một ví dụ LocalContainerEntityManagerFactoryBeanEntityManager.Làm cách nào để bắt đầu giao dịch theo cách thủ công trên EntityManager được chia sẻ trong Spring?

Để nhanh chóng thả nội dung đầy đủ bảng, tôi muốn chạy đoạn mã sau:

@Service 
public class DatabaseService { 
    @Autowired 
    private EntityManager em; 

    @Transactional 
    public void clear() { 
     em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate(); 
    } 
} 

Kết quả:

ERROR org.springframework.integration.handler.LoggingHandler: javax.persistence.TransactionRequiredException: Executing an update/delete query 
    at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71) 
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) 
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:744) 

Nếu tôi thực hiện thay đổi này:

public void clear() { 
    em.getTransaction().begin(); 
    em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate(); 
} 

Kết quả:

ERROR org.springframework.integration.handler.LoggingHandler: java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead 
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:245) 
    at com.sun.proxy.$Proxy84.getTransaction(Unknown Source) 
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) 
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:744) 

Tôi cũng đã cố gắng vào mùa xuân-data-JPA, nhưng cũng thất bại:

public interface MyRepository extends CrudRepository<MyEntity, Integer> { 
    @Query(value = "TRUNCATE TABLE MyTable", nativeQuery = true) 
    @Modifying 
    public void clear(); 
} 

Vì vậy, làm thế nào tôi có thể tạo một giao dịch và chạy truncate trong bối cảnh mùa xuân được chia sẻ?

Việc áp dụng Mùa xuân đang bắt đầu sử dụng: SpringApplication.run(AppConfig.class, args); có:

@Bean 
public JpaTransactionManager transactionManager() { 
    return new JpaTransactionManager(emf); 
} 
+0

Vui lòng đăng toàn bộ stacktraces kể cả do. – m3th0dman

+3

Thay vào đó, không sử dụng '@ Autowired' sử dụng' @ PersistenceContext'. –

+0

'@ PersistenceContext' không thay đổi gì cả. Stacktrace được cập nhật ở trên. – membersound

Trả lời

25

Bạn nên sử dụng TransactionTemplate đối tượng để quản lý giao dịch phải nhất thiết:

transactionTemplate.execute(new TransactionCallbackWithoutResult() { 
     @Override 
     protected void doInTransactionWithoutResult(TransactionStatus status) { 
      em.createNativeQuery("TRUNCATE TABLE MyTable).executeUpdate(); 
     } 
    }); 

Để tạo TransactionTemplate chỉ sử dụng tiêm PlatformTransactionManager:

transactionTemplate = new TransactionTemplate(platformTransactionManager); 

Và nếu bạn muốn sử dụng giao dịch mới chỉ gọi

transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); 
2

Là một workaround bây giờ tôi đã tạo ra một mới EntityManager rõ ràng bằng cách sử dụng EMF, và bắt đầu giao dịch bằng tay.

@Autowired 
private EntityManagerFactory emf; 

public void clearTable() { 
    EntityManager em = emf.createEntityManager(); 
    EntityTransaction tx = em.getTransaction(); 
    tx.begin(); 
    em.createNativeQuery("TRUNCATE TABLE MyTable).executeUpdate(); 
    tx.commit(); 
    em.close(); 
} 

Điều đó có lẽ không lý tưởng, nhưng hoạt động trong thời điểm này.

+1

Không có lý do tại sao '@ Transactional' không hoạt động, phải có điều gì đó sai với thiết lập của bạn. Ngoài ra cả hai giải pháp là giải pháp thay vì thực sự giải quyết vấn đề. Một điều tôi tự hỏi là bạn đã sử dụng đúng '@ Transactional' một từ mùa xuân và không phải là mới hơn từ JEE7? –

+1

Tôi sử dụng javax – membersound

+0

Và là API trong classpath của bạn hay chỉ là một phụ thuộc được cung cấp? Ngoài ra, bạn không sử dụng giao diện để đảm bảo rằng bạn bật proxy lớp ... Cuối cùng, bạn có thể thêm toàn bộ stacktrace vào bài đăng của mình không? –

3

JPA dữ liệu mùa xuân tự động chạy phương thức CRUD trong các giao dịch cho bạn (mà không cần phải thiết lập bất cứ điều gì ngoại trừ một người quản lý giao dịch). Nếu bạn muốn sử dụng giao dịch cho các phương pháp truy vấn của bạn, bạn chỉ có thể thêm @Transactional đến những:

interface MyRepository extends CrudRepository<MyEntity, Integer> { 

    @Transactional 
    @Modifying 
    @Query(value = "TRUNCATE TABLE MyTable", nativeQuery = true) 
    void clear(); 
} 

Trên một lưu ý tổng quát hơn, những gì bạn đã tuyên bố đây là một cách logic tương đương với CrudRepository.deleteAll(), ngoại trừ việc nó (lời tuyên bố của bạn) không tôn vinh thác cấp JPA. Vì vậy, tôi tự hỏi đó thực sự là những gì bạn định làm. Nếu bạn đang sử dụng Spring Boot, thiết lập kích hoạt và quản lý giao dịch sẽ được xử lý cho bạn.

Nếu bạn muốn sử dụng @Transactional vào mức độ dịch vụ, bạn cần phải thiết lập cả một JpaTransactionManager kích hoạt chú thích quản lý dựa trên giao dịch thông qua một trong hai <tx:annotation-driven /> hoặc @EnableTransactionManagement (trông giống như kích hoạt là mảnh mất tích trên nỗ lực của bạn để tạo ra các giao dịch trên lớp dịch vụ).

+0

Tôi nghĩ rằng bằng cách sử dụng @transactional có nghĩa là mùa xuân sẽ tự động xử lý các cam kết của bạn và tuôn ra mặc dù. – obesechicken13

+0

Tôi nghi ngờ rằng khóa không được thiết lập trong Spring. Về cơ bản, Spring đang quản lý người quản lý thực thể cho bạn (vì vậy sẽ không cho phép bạn quản lý các giao dịch của riêng bạn), nhưng bạn đã không nói cho nó cách quản lý các giao dịch. –

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