Pegas - Tidak Ada EntityManager dengan transaksi aktual yang tersedia untuk utas saat ini - tidak dapat secara andal memproses panggilan 'bertahan'

137

Saya mendapatkan kesalahan ini ketika mencoba memanggil metode "bertahan" untuk menyimpan model entitas ke database di aplikasi web Spring MVC saya. Tidak dapat menemukan pos atau laman mana pun di internet yang dapat dikaitkan dengan kesalahan khusus ini. Sepertinya ada sesuatu yang salah dengan kacang EntityManagerFactory tapi saya cukup baru untuk pemrograman Spring jadi bagi saya sepertinya semuanya diinisialisasi dengan baik dan menurut berbagai artikel tutorial di web.

dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
 http://www.springframework.org/schema/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
 http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-4.0.xsd
  http://www.springframework.org/schema/jdbc
  http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
  http://www.springframework.org/schema/data/jpa
  http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
  http://www.springframework.org/schema/data/repository
  http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd
  http://www.springframework.org/schema/jee
  http://www.springframework.org/schema/jee/spring-jee-3.2.xsd">

    <context:component-scan base-package="wymysl.Controllers" />
    <jpa:repositories base-package="wymysl.repositories"/> 
    <context:component-scan base-package="wymysl.beans" /> 
    <context:component-scan base-package="wymysl.Validators" /> 
    <bean
     class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
     <bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>

     <bean id="passwordValidator" class="wymysl.Validators.PasswordValidator"></bean>

     <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
        <property name="username" value="system" />
        <property name="password" value="polskabieda1" />
    </bean>

 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml" />
    <property name="dataSource" ref="dataSource" />

    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
            <property name="showSql" value="true" />
            <property name="generateDdl" value="false" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.max_fetch_depth">3</prop>
            <prop key="hibernate.jdbc.fetch_size">50</prop>
            <prop key="hibernate.jdbc.batch_size">10</prop>
        </props>
    </property>
</bean>

    <mvc:annotation-driven />

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:messages" />
</bean>

    <bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
             <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>


    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
        <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>

    <mvc:resources mapping="/resources/**" location="/resources/" />
    <mvc:resources mapping="/resources/*" location="/resources/css/"  
    cache-period="31556926"/>



</beans>

RegisterController.java

@Controller
public class RegisterController {

    @PersistenceContext
    EntityManager entityManager;

    @Autowired
    PasswordValidator passwordValidator;

    @InitBinder
    private void initBinder(WebDataBinder binder) {
        binder.setValidator(passwordValidator);
    }

    @RequestMapping(value = "/addUser", method = RequestMethod.GET)
    public String register(Person person) {


        return "register";

    }

    @RequestMapping(value = "/addUser", method = RequestMethod.POST)
    public String register(@ModelAttribute("person") @Valid @Validated Person person, BindingResult result) {
        if(result.hasErrors()) {
            return "register";
        } else {
            entityManager.persist(person);
            return "index";

        }




    }
Michał Bil
sumber
1
Seperti yang dikatakan kesalahan, tidak ada transaksi. Beri anotasi metode pendaftaran dengan @Transaction.
Rohit

Jawaban:

260

Saya memiliki masalah yang sama dan saya menjelaskan metode yang digunakan @Transactionaldan berhasil.

UPDATE: memeriksa dokumentasi pegas sepertinya secara default PersistenceContext bertipe Transaction, jadi itu sebabnya metode tersebut harus bersifat transaksional ( http://docs.spring.io/spring/docs/current/spring-framework-reference/ html / orm.html ):

Anotasi @PersistenceContext memiliki tipe atribut opsional, yang standarnya adalah PersistenceContextType.TRANSACTION. Default ini adalah apa yang Anda butuhkan untuk menerima proxy EntityManager bersama. Alternatifnya, PersistenceContextType.EXTENDED, adalah urusan yang sama sekali berbeda: Ini menghasilkan apa yang disebut extended EntityManager, yang tidak aman untuk benang dan karenanya tidak boleh digunakan dalam komponen yang diakses secara bersamaan seperti kacang singleton yang dikelola Spring. Extended EntityManagers hanya seharusnya digunakan dalam komponen stateful yang, misalnya, berada dalam satu sesi, dengan siklus hidup EntityManager tidak terikat pada transaksi saat ini tetapi lebih sepenuhnya tergantung pada aplikasi.

mlg
sumber
71
Jika sebuah metode tanpa @Transactionalannosi memanggil metode dengan @Transactionalanotasi di classfile yang sama, Anda juga akan terkejut oleh kesalahan ini (itulah yang saya hadapi).
Jacob van Lingen
5
Saya membubuhi keterangan kelas layanan @Transactional, yang juga berfungsi. Tidak yakin apakah itu cara yang tepat untuk pergi tetapi sepertinya itu berfungsi dengan baik ...
milosmns
8
Hal lain yang perlu disebutkan adalah bahwa penjelasan ini harus digunakan untuk metode publik karena tidak berfungsi sebaliknya.
Yuriy Kravets
7
Ingat, tolong, bahwa @Transactional hanya bekerja pada metode publik.
Andrei_N
7
FYI ini membutuhkan javax.transaction.Transactional annotation (bukan Spring).
java-addict301
85

Saya mendapat pengecualian ini ketika mencoba menggunakan metode kustom deleteBy di repositori data spring. Operasi itu dicoba dari kelas uji JUnit.

Pengecualian tidak terjadi saat menggunakan @Transactionalanotasi di tingkat kelas JUnit.

Kishore Guruswamy
sumber
8
Saya berada dalam situasi yang sama, alih-alih membubuhi keterangan pada kelas tes, saya memberi anotasi pada metode layanan sehingga itu menetes ke bawah bahkan jika itu bukan ujian.
Paul Nelson Baker
@Transactionaldi tingkat kelas dapat menutupi kemungkinan masalah pengujian yang memanipulasi transaksi berbeda di layanan Anda.
Zon
1
Saya menggunakan @Trasactionalmetode repositori karena ini adalah tempat saya berinteraksi dengan database dan berfungsi dengan baik.
Harish Kumar Saini
22

Kesalahan ini membuat saya rubah selama tiga hari, situasi yang saya hadapi menghasilkan kesalahan yang sama. Mengikuti semua saran yang bisa saya temukan, saya bermain dengan konfigurasi tetapi tidak berhasil.

Akhirnya saya menemukannya, bedanya, Layanan yang saya jalankan terkandung dalam tabung yang sama, masalahnya ternyata AspectJ tidak memperlakukan instantiasi Layanan yang sama. Akibatnya proksi hanya memanggil metode yang mendasarinya tanpa semua sihir Spring normal dieksekusi sebelum metode memanggil.

Pada akhirnya, anotasi @Scope yang ditempatkan pada layanan sesuai contoh menyelesaikan masalah:

@Service
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
@Transactional
public class CoreServiceImpl implements CoreService {
    @PersistenceContext
    protected EntityManager entityManager;

    @Override
    public final <T extends AbstractEntity> int deleteAll(Class<T> clazz) {
        CriteriaDelete<T> criteriaDelete = entityManager.getCriteriaBuilder().createCriteriaDelete(clazz);
        criteriaDelete.from(clazz);
        return entityManager.createQuery(criteriaDelete).executeUpdate();
    }

}

Metode yang saya posting adalah metode delete tetapi penjelasannya mempengaruhi semua metode kegigihan dengan cara yang sama.

Saya harap pos ini membantu orang lain yang mengalami masalah yang sama saat memuat layanan dari toples

Chris March
sumber
Menambahkan @Scope(proxyMode = ScopedProxyMode.INTERFACES)ke kelas DAO yang mengimplementasikan antarmuka sangat penting. Saya menghabiskan sepanjang hari untuk mencari tahu kesalahan ini dan solusi Anda adalah satu-satunya yang berfungsi. Terima kasih banyak!
Thach Van
1
Satu L'annotation dari jawaban Anda baru saja menyelamatkan saya mungkin sekitar 3 hari. Saya baru saja mengalami kekuatan edenema yang sebenarnya. Дякс.
Oleksii Kyslytsyn
11

Saya memiliki kesalahan yang sama karena saya beralih dari konfigurasi XML ke java.

Intinya, saya tidak melakukan migrasi <tx:annotation-driven/>tag, seperti yang disarankan oleh Stone Feng.

Jadi saya baru saja menambahkan @EnableTransactionManagementseperti yang disarankan di sini Menyiapkan Anotasi Didorong Transaksi di Spring di @Configuration Class , dan berfungsi sekarang

Sergej Werfel
sumber
8

boardRepo.deleteByBoardId (id);

Menghadapi masalah yang sama. GOT javax.persistence.TransactionRequiredException: Tidak Ada Pengelola Entitas dengan transaksi aktual yang tersedia untuk utas saat ini

Saya mengatasinya dengan menambahkan penjelasan @Transaksional di atas controller / service.

Vikram S
sumber
7

Aku punya masalah yang sama dan saya menambahkan tx:annotation-drivendalam applicationContext.xmldan bekerja.

Batu Feng
sumber
4

Saya memiliki kesalahan yang sama ketika mengakses metode yang sudah transaksional-dijelaskan dari metode non-transaksional dalam komponen yang sama:

Before:
    @Component
    public class MarketObserver {
        @PersistenceContext(unitName = "maindb")
        private EntityManager em;

        @Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
        public void executeQuery() {
          em.persist(....);
        }


        @Async
        public void startObserving() {
          executeQuery(); //<-- Wrong
        }
    }

    //In another bean:
     marketObserver.startObserving();

Saya memperbaiki kesalahan dengan memanggil executeQuery () pada komponen referensi-sendiri:

Fixed version:
    @Component
    public class MarketObserver {
        @PersistenceContext(unitName = "maindb")
        private EntityManager em;

        @Autowired
        private GenericApplicationContext context;

        @Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
        public void executeQuery() {
          em.persist(....);
        }


        @Async
        public void startObserving() {
          context.getBean(MarketObserver.class).executeQuery(); //<-- Works
        }
    }
YDZOGODOQ
sumber
3

Menambahkan org.springframework.transaction.annotation.Transactionalanotasi di tingkat kelas untuk kelas tes memperbaiki masalah bagi saya.

Leo
sumber
3

Hanya catatan untuk pengguna lain yang mencari jawaban untuk kesalahan Anda. Masalah umum lainnya adalah:

Anda biasanya tidak dapat memanggil @transactionalmetode dari dalam kelas yang sama.

(Ada cara dan cara menggunakan AspectJ tetapi refactoring akan jauh lebih mudah)

Jadi Anda akan membutuhkan kelas panggilan dan kelas yang memegang @transactionalmetode.

sparkyspider
sumber
2

Bagi kami, masalahnya datang ke pengaturan konteks yang sama di beberapa file konfigurasi. Periksa Anda tidak menduplikasi yang berikut dalam beberapa file konfigurasi.

<context:property-placeholder location="classpath*:/module.properties"/>
<context:component-scan base-package="...." />
Nick West
sumber
2

Saya memiliki kode kesalahan yang sama ketika saya menggunakan @Transactionmetode / actionlevel yang salah.

methodWithANumberOfDatabaseActions() { 
   methodA( ...)
   methodA( ...)
}

@Transactional
void methodA( ...) {
  ... ERROR message
}

Saya harus meletakkan @Transactionaltepat di atas metode methodWithANumberOfDatabaseActions(), tentu saja.

Itu memecahkan pesan kesalahan dalam kasus saya.

cara lain
sumber
0

Saya menghapus mode dari

<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />

untuk membuat ini bekerja

Ropo
sumber
0

Saya memiliki masalah ini selama berhari-hari dan tidak ada yang saya temukan di mana pun di internet yang membantu saya, saya memposting jawaban saya di sini jika itu membantu orang lain.

Dalam kasus saya, saya sedang mengerjakan layanan microser yang dipanggil melalui remoting, dan penjelasan @Transaksional saya di tingkat layanan tidak diambil oleh proxy jarak jauh.

Menambahkan kelas delegasi antara layanan dan lapisan dao dan menandai metode delegasi sebagai transaksional memperbaikinya untuk saya.

fleeblewidget
sumber
0

Ini membantu kami, mungkin itu bisa membantu orang lain di masa depan. @Transactiontidak bekerja untuk kita, tetapi ini berhasil:

@ConditionalOnMissingClass("org.springframework.orm.jpa.JpaTransactionManager")

JLane
sumber
0

Jika Anda memiliki

@Transactional // Spring Transactional
class MyDao extends Dao {
}

dan kelas super

class Dao {
    public void save(Entity entity) { getEntityManager().merge(entity); }
}

dan kamu menelepon

@Autowired MyDao myDao;
myDao.save(entity);

Anda tidak akan mendapatkan Spring TransactionInterceptor (yang memberi Anda transaksi).

Ini adalah hal yang perlu kamu lakukan:

@Transactional 
class MyDao extends Dao {
    public void save(Entity entity) { super.save(entity); }
}

Luar biasa tapi benar.

pengguna2006754
sumber