标签:style http io os 使用 java ar strong for
尽管现在开源的框架已经非常优秀,但是缺乏统一的标准有违软件开源的初衷,因此Sun公司的JCP组织发布了Java EE的JPA标准,并统一ORM规则、JPQL查询语言、子查询、高级查询和批量处理等操作。推出JPA规范有两点原因:一是,希望简化现有的SE和EE工作,特别是EJB3.0的推出,使得企业级项目的开发推向更高的层次(EJB3.0已经非常优秀,但是由于时间的问题,并且Spring已经占领了市场);二是,希望业界有一个统一的标准,就像当年JDBC推出一样,只实现接口,其余API的实现交给项目厂商或者组织去完成。
实际项目开发应该尽量使用JPA的API编程,为什么要这样做?JPA是一个规范,不是产品,最终实现交给Hibernate这些ORM框架去实现,即使以后我们要改变ORM的底层,也只需要简单更改一下配置即可,JPA还是属于javax.persistence.*的包里面,稍微有些不同的是主键的生成策略不同的ORM规范有所差异,但基本原理还是一样。
下面将分hibernate实现和整合Spring实现两种案例说明JPA整合的好处。
由于Spring、Hibernate和log4j的maven配置比较繁琐,这里只提供版本管理:
<properties>
<!--Spring版本号-->
<spring.version>4.0.5.RELEASE</spring.version>
<!--hibernate-->
<hibernate.version>4.3.0.Final</hibernate.version>
<!--log4j日志文件管理包版本-->
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<!--项目编码级别-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--spring jpa-->
<spring-data-jpa.version>1.4.1.RELEASE</spring-data-jpa.version>
<hibernate-jpa-api.version>1.0.1.Final</hibernate-jpa-api.version>
</properties>
POJO实体
由于使用注解方式创建,因此本文将不创建orm.xml文件,并且JPA的注解也非常容易看懂,因此注解内容不做详述,下面创建一个用户实体对象,对应数据库中的表为t_user;
import javax.persistence.*;
import java.io.Serializable;
/**
* @author Barudisshu
*/
@Entity(name = "USER")
@Table(name = "t_user",uniqueConstraints = {@UniqueConstraint(columnNames = {"username"})})
public class UserInfo implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 希望用户名是唯一的
@Basic
@Column(name = "username")
private String username;
@Basic
@Column(name = "password")
private String password;
// 如果Id生成策略被指定,不应该有带参数的构造函数
// 省略getter和setter方法
}
因为@Id中的Id字段是唯一的,如果生成策略已经指定,使用persist(Object obj)方法时将抛出异常,因此,要么改为merge方法,要么去掉@GeneratedVale注解,因为persist会寻找游离态的实体是根据Id进行标识,如果没有则自行创建。
默认persistence.xml文件处于根目录的META-INF文件下,并且名称固定,如果使用想使用Maven指定,需要配置ant插件:
<plugins>
<!--如果想指定persistence.xml位置,则添加如下插件-->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>copy-test-persistence</id>
<phase>process-test-resources</phase>
<configuration>
<tasks>
<!--backup the "proper" persistence.xml-->
<copy file="${project.build.outputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml.proper"/>
<!--replace the "proper" persistence.xml with the "test" version-->
<copy file="${project.build.testOutputDirectory}/META-INF/persistence.xml" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>restore-persistence</id>
<phase>prepare-package</phase>
<configuration>
<tasks>
<!--restore the "proper" persistence.xml-->
<copy file="${project.build.outputDirectory}/META-INF/persistence.xml.proper" tofile="${project.build.outputDirectory}/META-INF/persistence.xml"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
OK,前面已经说过,只使用注解方式,不使用xml方式,所以persistence.xml使用类加载的方式。
<?xml version=‘1.0‘ encoding=‘utf-8‘?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<!--持久化单元,使用JTA必须架构在JBOSS服务器上-->
<persistence-unit name="person_pu" transaction-type="RESOURCE_LOCAL">
<!--hibernate jpa提供者为HibernatePersistenceProvider-->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!--持久化对象-->
<class>ls.jpa.entity.UserInfo</class>
<properties>
<!--基本属性-->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/db_test"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="***"/>
<!--hibernate配置-->
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
注意:JPA2.0和JPA1.0有较大差别,JPA2.0是提供了类型安全的查询机制、丰富的表达式等功能,并且已经从EJB中独立开来。
单元测试类不用显式加载persistence.xml文件,到底persistence.xml文件是如何加载的为什么名称是固定的?笔者找了很久,原来是是在org.hibernate.jpa.boot.internal.PersistenceXmlParser类下定义的,如果单纯从Persistence类下是找不到的,因为hibernate.jpa.boot包下会加载所有配置文件并转换为properties属性存储在Map中,然后通过工具类或者通过ClassLoader进行属性访问。下面为单元测试代码:
import ***;
/**
* @author Barudisshu
*/
public class LogonTest {
private static final Logger logger = Logger.getLogger(LogonTest.class);
private static final String PERSISTENCE_UNIT_NAME = "person_pu";
@Test
public void simpleTests(){
// Obtaining an entity manager
EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager entityManager = factory.createEntityManager();
// Read the existing entries and write to console
TypedQuery<UserInfo> query = entityManager.createQuery("select u from USER u", UserInfo.class);
List<UserInfo> userList = query.getResultList();
// List user name
for (UserInfo userInfo : userList) {
logger.info(userInfo.getUsername());
}
logger.info("Size: " + userList.size());
// Simple transaction
entityManager.getTransaction().begin();
UserInfo userInfo = new UserInfo();
userInfo.setUsername("Barudisshu");
userInfo.setPassword("88888888");
entityManager.persist(userInfo);
entityManager.getTransaction().commit();
// Close the EM and EMF when done
entityManager.close();
factory.close();
}
}
单纯使用JPA很难满足业务上的需求,因此可以通过Spring进行集成,进而架构成为逻辑清晰的业务层次。首先添加相应的Maven管理包,如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data-jpa.version}</version>
</dependency>
为了达到分层的架构,一下分别添加Dao层和Service层,代码清单如下:
Dao层,自动装配持久化上下文:
import ***;
/**
* @author Barudisshu
*/
@Repository
public class UserDao {
@PersistenceContext
private EntityManager em;
@Transactional
public UserInfo save(UserInfo userInfo){
em.persist(userInfo);
return userInfo;
}
}
Service层,创建服务:
import ***;
/**
* @author Barudisshu
*/
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public UserInfo create(String name,String password){
UserInfo userInfo = new UserInfo();
userInfo.setUsername(name);
userInfo.setPassword(password);
return userDao.save(userInfo);
}
}
上述代码没有使用JpaTemplate模版,自spring3.1之后就没有了,可能是JPA规范做得足够好的原因,就像自spring3.2.x之后不再支持HibernateTemplate一样。
Spring整合Hibernate时,Spring可以通过容器来管理Hibernate的SessionFactory;类似地,Spring整合JPA时,Spring可以通过容器管理JPA的EntityManagerFactory。Spring为JPA EntityManagerFactory管理提供了两种方式:
LocalEntityMangerFactoryBean功能比较有限,只能通过persistence.xml内容的属性构建,因此不能使用Spring容器中已有的DataSource,也不能切换全局事务。而LocalContainerEntityManagerFactoryBean则刚好弥补了这方面的不足,并且可以使用Spring容器中已有的数据源,这样persistence.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="ls.jpa"/>
<bean id="emf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<!--注入JPA持久化单元-->
<property name="persistenceUnitName" value="person_pu"/>
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>
<!--开启AOP监听-->
<aop:aspectj-autoproxy expose-proxy="true"/>
<!--使用声明式事务-->
<tx:annotation-driven transaction-manager="txManager"/>
</beans> OK,所有配置已经完成,下面进行简单的单元测试:
import ***;
/**
* @author Barudisshu
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-config.xml"})
@Transactional
@TransactionConfiguration(transactionManager = "txManager",defaultRollback = true)
public class SimpleTest {
private static final Logger logger = Logger.getLogger(SimpleTest.class);
@Autowired
private UserService userService;
@Test
public void userTests(){
UserInfo userInfo = userService.create("Barudisshu","liter");
logger.info(JSON.toJSONString(userInfo));
}
}
单元测试绿条通过后,打开数据库可以看到,已经自动为你创建t_user用户表:
Well done!
标签:style http io os 使用 java ar strong for
原文地址:http://my.oschina.net/Barudisshu/blog/314843