Hibernate 5 事务未由 Spring 4 启动
Hibernate 5 Transaction not started by Spring 4
基于this tutorial,我试图用Spring4来管理Hibernate 5事务。似乎到达session.get()方法时事务还没有启动。 Spring 如何知道何时开始和结束交易? @Transactional 注释不应该正是这样做的吗?
实体
package coproject.cpweb.utils.db.entities;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import coproject.cpweb.utils.db.entities.Project;
import coproject.cpweb.utils.db.entities.User;
@Entity
@Table( name = "users" )
public class Cbtion {
@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
private Integer id;
@ManyToOne
private Project project;
@ManyToOne
private User creator;
private Date creationDate;
private String title;
private String description;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
public User getCreator() {
return creator;
}
public void setCreator(User creator) {
this.creator = creator;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
DAO
package coproject.cpweb.utils.db.daos;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import coproject.cpweb.utils.db.entities.User;
@Service
public class CbtionDAO {
@Autowired
SessionFactory sessionFactory;
public void saveUser(User user) {
Session session = sessionFactory.getCurrentSession();
User user_indb = session.get(User.class,user.getId());
if(user_indb == null) {
session.save(user);
}
else {
user = user_indb;
}
}
public User getUser(Integer id) {
Session session = sessionFactory.getCurrentSession();
User user = session.get(User.class,id);
return user;
}
}
服务
package coproject.cpweb.utils.db.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import coproject.cpweb.utils.DbServicesIf;
import coproject.cpweb.utils.db.daos.CbtionDAO;
import coproject.cpweb.utils.db.entities.User;
@Service
public class DbServicesImp implements DbServicesIf{
@Autowired
private CbtionDAO cbtionDAO;
@Transactional
public void saveUser(User user) {
cbtionDAO.saveUser(user);
}
@Transactional
public User getUser(Integer id) {
return cbtionDAO.getUser(id);
}
}
上下文beans.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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd" >
<tx:annotation-driven />
<context:component-scan base-package="coproject.cpweb.utils.db.entities" />
<context:component-scan base-package="coproject.cpweb.utils.db.daos" />
<context:component-scan base-package="coproject.cpweb.utils.db.services" />
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="jaof" />
<property name="password" value="iris" />
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan">
<list>
<value>coproject.cpweb.utils.db.entities</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager" >
<property name="sessionFactory" ref="mySessionFactory" />
</bean>
</beans>
主要
package coproject.cploc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import coproject.cpweb.utils.db.entities.User;
import coproject.cpweb.utils.db.services.DbServicesImp;
public class FillRandomDb {
public static void main(String[] args) throws Exception {
@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// TEST String[] bean_names = context.getBeanDefinitionNames();
DbServicesImp dbServices = (DbServicesImp) context.getBean("dbServicesImp");
User user = new User();
user.setUsername("johndoe");
user.setFirstname("John");
user.setLastname("Doe");
dbServices.saveUser(user);
User user_ret = dbServices.getUser(user.getId());
System.out.println(user_ret.getFirstname());
}
}
堆栈
nov 29, 2015 1:45:37 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@506e6d5e: startup date [Sun Nov 29 13:45:37 CE
T 2015]; root of context hierarchy
nov 29, 2015 1:45:37 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans.xml]
nov 29, 2015 1:45:38 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
nov 29, 2015 1:45:38 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {5.0.2.Final}
nov 29, 2015 1:45:38 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
nov 29, 2015 1:45:38 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
nov 29, 2015 1:45:38 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.0.0.Final}
nov 29, 2015 1:45:39 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
nov 29, 2015 1:45:45 PM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000227: Running hbm2ddl schema export
nov 29, 2015 1:45:46 PM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
nov 29, 2015 1:45:46 PM org.springframework.orm.hibernate5.HibernateTransactionManager afterPropertiesSet
INFO: Using DataSource [org.apache.commons.dbcp.BasicDataSource@5e1d03d7] of Hibernate SessionFactory for HibernateTransactionMana
ger
Exception in thread "main" org.hibernate.HibernateException: get is not valid without active transaction
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:33
4)
at com.sun.proxy.$Proxy23.get(Unknown Source)
at coproject.cpweb.utils.db.daos.CbtionDAO.saveUser(CbtionDAO.java:19)
at coproject.cpweb.utils.db.services.DbServicesImp.saveUser(DbServicesImp.java:20)
at coproject.cpweb.utils.db.services.DbServicesImp$$FastClassBySpringCGLIB$$cd649fcb.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281
)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at coproject.cpweb.utils.db.services.DbServicesImp$$EnhancerBySpringCGLIB$288f15.saveUser(<generated>)
at coproject.cploc.FillRandomDb.main(FillRandomDb.java:24)
DAO class 应该注解为@Repository。
尝试更改文件中的这一行 context beans.xml:
<prop key="hibernate.current_session_context_class">thread</prop>
这一行:
<prop key="current_session_context_class">thread</prop >
为了注释支持,在您的 spring 配置 bean 中添加:
<tx:annotation-driven transaction-manager="transactionManager" mode="proxy" proxy-target-class="true" />
基于this tutorial,我试图用Spring4来管理Hibernate 5事务。似乎到达session.get()方法时事务还没有启动。 Spring 如何知道何时开始和结束交易? @Transactional 注释不应该正是这样做的吗?
实体
package coproject.cpweb.utils.db.entities;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import coproject.cpweb.utils.db.entities.Project;
import coproject.cpweb.utils.db.entities.User;
@Entity
@Table( name = "users" )
public class Cbtion {
@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
private Integer id;
@ManyToOne
private Project project;
@ManyToOne
private User creator;
private Date creationDate;
private String title;
private String description;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
public User getCreator() {
return creator;
}
public void setCreator(User creator) {
this.creator = creator;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
DAO
package coproject.cpweb.utils.db.daos;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import coproject.cpweb.utils.db.entities.User;
@Service
public class CbtionDAO {
@Autowired
SessionFactory sessionFactory;
public void saveUser(User user) {
Session session = sessionFactory.getCurrentSession();
User user_indb = session.get(User.class,user.getId());
if(user_indb == null) {
session.save(user);
}
else {
user = user_indb;
}
}
public User getUser(Integer id) {
Session session = sessionFactory.getCurrentSession();
User user = session.get(User.class,id);
return user;
}
}
服务
package coproject.cpweb.utils.db.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import coproject.cpweb.utils.DbServicesIf;
import coproject.cpweb.utils.db.daos.CbtionDAO;
import coproject.cpweb.utils.db.entities.User;
@Service
public class DbServicesImp implements DbServicesIf{
@Autowired
private CbtionDAO cbtionDAO;
@Transactional
public void saveUser(User user) {
cbtionDAO.saveUser(user);
}
@Transactional
public User getUser(Integer id) {
return cbtionDAO.getUser(id);
}
}
上下文beans.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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd" >
<tx:annotation-driven />
<context:component-scan base-package="coproject.cpweb.utils.db.entities" />
<context:component-scan base-package="coproject.cpweb.utils.db.daos" />
<context:component-scan base-package="coproject.cpweb.utils.db.services" />
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="jaof" />
<property name="password" value="iris" />
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan">
<list>
<value>coproject.cpweb.utils.db.entities</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager" >
<property name="sessionFactory" ref="mySessionFactory" />
</bean>
</beans>
主要
package coproject.cploc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import coproject.cpweb.utils.db.entities.User;
import coproject.cpweb.utils.db.services.DbServicesImp;
public class FillRandomDb {
public static void main(String[] args) throws Exception {
@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// TEST String[] bean_names = context.getBeanDefinitionNames();
DbServicesImp dbServices = (DbServicesImp) context.getBean("dbServicesImp");
User user = new User();
user.setUsername("johndoe");
user.setFirstname("John");
user.setLastname("Doe");
dbServices.saveUser(user);
User user_ret = dbServices.getUser(user.getId());
System.out.println(user_ret.getFirstname());
}
}
堆栈
nov 29, 2015 1:45:37 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@506e6d5e: startup date [Sun Nov 29 13:45:37 CE
T 2015]; root of context hierarchy
nov 29, 2015 1:45:37 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans.xml]
nov 29, 2015 1:45:38 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
nov 29, 2015 1:45:38 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {5.0.2.Final}
nov 29, 2015 1:45:38 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
nov 29, 2015 1:45:38 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
nov 29, 2015 1:45:38 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.0.0.Final}
nov 29, 2015 1:45:39 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
nov 29, 2015 1:45:45 PM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000227: Running hbm2ddl schema export
nov 29, 2015 1:45:46 PM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
nov 29, 2015 1:45:46 PM org.springframework.orm.hibernate5.HibernateTransactionManager afterPropertiesSet
INFO: Using DataSource [org.apache.commons.dbcp.BasicDataSource@5e1d03d7] of Hibernate SessionFactory for HibernateTransactionMana
ger
Exception in thread "main" org.hibernate.HibernateException: get is not valid without active transaction
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:33
4)
at com.sun.proxy.$Proxy23.get(Unknown Source)
at coproject.cpweb.utils.db.daos.CbtionDAO.saveUser(CbtionDAO.java:19)
at coproject.cpweb.utils.db.services.DbServicesImp.saveUser(DbServicesImp.java:20)
at coproject.cpweb.utils.db.services.DbServicesImp$$FastClassBySpringCGLIB$$cd649fcb.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281
)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at coproject.cpweb.utils.db.services.DbServicesImp$$EnhancerBySpringCGLIB$288f15.saveUser(<generated>)
at coproject.cploc.FillRandomDb.main(FillRandomDb.java:24)
DAO class 应该注解为@Repository。
尝试更改文件中的这一行 context beans.xml:
<prop key="hibernate.current_session_context_class">thread</prop>
这一行:
<prop key="current_session_context_class">thread</prop >
为了注释支持,在您的 spring 配置 bean 中添加:
<tx:annotation-driven transaction-manager="transactionManager" mode="proxy" proxy-target-class="true" />