我正在使用Spring,JPA和Hibernate。这是我用来调试更大的JPA相关问题的玩具示例。但是,这个尝试持久化基本实体HelloBean
的简单示例似乎创建了分离对象。据我所知,在persist
对象上调用EntityManager
应该将实体设置为由持久化上下文管理。但是,它没有,merge
也不起作用。输出如下::
Starting...
Service found in context as: net.solasistim.hello.HelloService@3b7a687b
Hibernate: insert into HelloBean (message) values (?)
Is bean attached? = false
Hibernate: select hellobean0_.id as id1_0_0_, hellobean0_.message as message2_0_0_ from HelloBean hellobean0_ where hellobean0_.id=?
Is bean attached? = false
为简洁起见省略了导入。
Hello.java
::
public class Hello {
public static void main(String[] args) throws Exception {
ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
System.out.println("Starting...");
HelloService svc = (HelloService) context.getBean("helloService");
System.out.println("Service found in context as: " + svc);
HelloBean bean1 = new HelloBean();
bean1.setMessage("This is bean 1.");
HelloBean bean2 = new HelloBean();
bean2.setMessage("This is bean 2.");
svc.persist(bean2);
System.out.println("Is bean attached? = " + svc.isAttached(bean2));
HelloBean newBean = svc.merge(bean2);
System.out.println("Is bean attached? = " + svc.isAttached(newBean));
}
}
HelloService.java
::
@Service
@Transactional
public class HelloService {
@PersistenceContext private EntityManager em;
public void persist(HelloBean entity) {
em.persist(entity);
}
public HelloBean merge(HelloBean entity) {
return em.merge(entity);
}
public void delete(HelloBean entity) {
em.remove(entity);
}
public boolean isAttached(HelloBean entity) {
return em.contains(entity);
}
}
HelloBean.java
::
@Entity
public class HelloBean {
@Id
@GeneratedValue
private long id;
private String message;
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
pom.xml
::
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>net.solasistim.hello</groupId>
<artifactId>hello</artifactId>
<version>1</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.2.0.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.24</version>
</dependency>
</dependencies>
</project>
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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:component-scan base-package="net.solasistim.hello"/>
<context:annotation-config />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="my-persistence-unit"/>
</bean>
<!-- These two are needed for @Transactional annotations to be processed.
Nothing will be committed without them. -->
<tx:annotation-driven/>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
persistence.xml
::
<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="my-persistence-unit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.connection.driver_class"
value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url"
value="jdbc:mysql://localhost:3306/jpa_test" />
<property name="hibernate.connection.username"
value="root" />
<property name="hibernate.connection.password"
value="" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
</persistence-unit>
</persistence>
答案 0 :(得分:4)
虽然您的HelloService
是事务性的,但是一旦服务方法返回,事务就会被提交。这就是为什么实体不再在Hello#main
内进行管理。
尝试将输出语句添加到HelloService
的方法中,您将看到实体附加在这些方法中。
编辑:服务层通常需要交易性。在交易中做所有事情很少是明智的。注释main
方法不是一个好主意,因为只有在main方法返回后才会刷新持久化上下文 - 即在应用程序终止后。
您可以在事务服务方法中对附加的实体(您现在可能在main
中执行的操作)执行所需操作 - 就像HelloService
中的那些实体一样。此方法可以直接使用EntityManager
,也可以使用DAO。您可以使用@Transactional(propagation = Propagation.MANDATORY)
注释DAO的方法,以确保事务(由服务启动)可用。
处理UI等其他层中的分离实体很少有问题。如果已在服务层上方的层中更改了分离的实体,则需要在之后合并它。如果实体可能已在DB中更改,则需要重新/刷新它。