下面为我的工程目录结构:
其中persistence.xml是必须的,
<dependencies> <dependency> <groupId>org.apache.openjpa</groupId> <artifactId>openjpa-all</artifactId> <version>2.3.0</version> </dependency> <!--Servlet级别--> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> </dependency> </dependencies> <build> <finalName>${artifactId}</finalName> <resources> <resource> <directory>${basedir}/src/main/resources</directory> <filtering>true</filtering> </resource> </resources> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>openjpa-maven-plugin</artifactId> <version>1.1</version> <configuration> <includes>**/entities/*.class</includes> <excludes>**/entities/XML*.class</excludes> <addDefaultConstructor>true</addDefaultConstructor> <enforcePropertyRestrictions>true</enforcePropertyRestrictions> </configuration> <executions> <execution> <id>enhancer</id> <phase>process-classes</phase> <goals> <goal>enhance</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.apache.openjpa</groupId> <artifactId>openjpa</artifactId> <version>2.3.0</version> </dependency> </dependencies> </plugin> </plugins> </build>在pom.xml中添加相应的插件。
persistence.xml数据源和属性较为全面的配置
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> <persistence-unit name="TODS" transaction-type="RESOURCE_LOCAL"> <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider> <class>ls.jpa.chapter.entities.Employee</class> <!--自动加载所有实体--> <!--<exclude-unlisted-classes>false</exclude-unlisted-classes>--> <!--注解方式 or xml配置--> <!--<mapping-file>META-INF/orm.xml</mapping-file>--> <!--所有属性参考http://openjpa.apache.org/builds/2.2.1/apache-openjpa/docs/ref_guide_conf_openjpa.html--> <properties> <!--自动建表空间--> <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/> <!--数据源--> <property name="openjpa.ConnectionURL" value="jdbc:mysql://localhost:3306/db_test"/> <property name="openjpa.ConnectionUserName" value="root"/> <property name="openjpa.ConnectionPassword" value="****"/> <property name="openjpa.ConnectionDriverName" value="com.mysql.jdbc.Driver"/> <!--开启日志--> <property name="openjpa.Log" value="DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=TRACE"/> <!--<property name="openjpa.Log" value="none"/>--> <!--动态运行时--> <property name="openjpa.DynamicEnhancementAgent" value="false"/> <property name="openjpa.RemoteCommitProvider" value="sjvm" /> <property name="openjpa.RuntimeUnenhancedClasses" value="supported"/> <!-- 启用缓存,并且设置缓存的容量为5000,并且禁用软引用容量 --> <property name="openjpa.DataCache" value="true(CacheSize=5000, SoftReferenceSize=100)" /> <!-- 启用查询结果缓存,缓存的容量为1000,并且软引用的容量为100 --> <property name="openjpa.QueryCache" value="true(CacheSize=5000, SoftReferenceSize=100)" /> <!-- 缓存的数据存储类型 --> <property name="openjpa.QueryCompilationCache" value="true" /> <!-- 数据库连接工厂时的属性 QueryTimeout:JDBC驱动执行查询超时的时间,以秒为单位。 PrettyPrint:是否格式化输出SQL语句。 PrettyPrintLineLength:SQL每行输出的最大长度。 --> <property name="openjpa.ConnectionFactoryProperties" value="PrettyPrint=true, PrettyPrintLineLength=100" /> <!-- 查询结果一次转化为对象的最多个数,相当于JDBC的结果集对象Statement.set FetchSize。默认为-1,表示所有的查询对象立即初始化;0表示使用JDBC驱动默认的数值 --> <property name="openjpa.FetchBatchSize" value="-1" /> </properties> </persistence-unit> </persistence>
orm.xml对象-关联映射
<?xml version="1.0" encoding="UTF-8"?> <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" version="2.0"> <entity class="ls.jpa.chapter.entities.Employee" name="Emp"> <table name="t_employee"/> </entity> </entity-mappings>
首先建立实体类Employee:
import javax.persistence.*; import java.io.Serializable; /** * @author Barudisshu */ @Entity @Table(name = "t_employee") public class Employee implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY,generator = "EmployeeSeqXX") @SequenceGenerator(name = "EmployeeSeqXX", allocationSize = 1) private int id; private String name; private long salary; public Employee() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSalary() { return salary; } public void setSalary(long salary) { this.salary = salary; } }建立对应服务类:
import javax.persistence.*; import java.util.List; /** * @author Barudisshu */ public class EmployeeService { protected EntityManager em; public EmployeeService(EntityManager em) { this.em = em; } public Employee createEmployee(int id, String name, long salary) { Employee emp = new Employee(); emp.setId(id); emp.setName(name); emp.setSalary(salary); Query query = em.createNativeQuery("INSERT INTO db_test.t_employee(id,name,salary) VALUES (?, ?, ?)"); query.setParameter(1, emp.getId()); query.setParameter(2, emp.getName()); query.setParameter(3, emp.getSalary()); int row = query.executeUpdate(); if (row < 1) return null; else // em.merge(emp); return emp; } public void removeEmployee(int id) { Employee emp = findEmployee(id); if (emp != null) { em.remove(emp); } } public Employee raiseEmployeeSalary(int id, long raise) { Employee emp = em.find(Employee.class, id); if (emp != null) { emp.setSalary(emp.getSalary() + raise); } return emp; } public Employee findEmployee(int id) { return em.find(Employee.class, id); } public List<Employee> findAllEmployees() { TypedQuery<Employee> query = em.createQuery("select e from Emp e", Employee.class); return query.getResultList(); } }
单元测试类:
import ***; public class EmployeeTest { private static final Logger logger = Logger.getLogger(EmployeeTest.class); private static final String PERSISTENCE_UNIT_NAME = "TODS"; private EntityManagerFactory emf; private EntityManager em; private EmployeeService service; @Before public void setUp() { // Obtaining an entities manager emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME); em = emf.createEntityManager(); service = new EmployeeService(em); } @Test public void simpleTests() { // Read the existing entries and write to console TypedQuery<Employee> query = em.createQuery("select e from Emp e", Employee.class); List<Employee> employeeList = query.getResultList(); // List employee name logger.info("Entities: " + JSON.toJSON(employeeList)); logger.info("Size: " + employeeList.size()); // Simple transaction em.getTransaction().begin(); Employee employee = new Employee(); employee.setName("Barudisshu"); employee.setSalary(3300); em.persist(employee); em.getTransaction().commit(); // Close the EM and EMF when done em.close(); emf.close(); } @Test public void serviceTests() { // Create and persist an employee em.getTransaction().begin(); Employee emp = service.createEmployee(158, "John Doe", 45000); em.getTransaction().commit(); logger.info("Persisted: " + emp); // Find specific employee emp = service.findEmployee(158); logger.info("Found: " + emp); // Find all employees List<Employee> emps = service.findAllEmployees(); logger.info("Found all: " + JSON.toJSON(emps)); // Update the employee em.getTransaction().begin(); emp = service.raiseEmployeeSalary(158, 1000); em.getTransaction().commit(); logger.info("Updated: " + JSON.toJSON(emp)); // Remove an employee em.getTransaction().begin(); service.removeEmployee(158); em.getTransaction().commit(); logger.info("Remove employee 158"); // Close the EM and EMF when done em.close(); emf.close(); } }注意以上代码EmployeeService类中的注释em.merge(emp);,理论上在Hibernate上运行是可以通过的,但在openJPA上会报:
The instance life cycle is in PNewState state and hence an existing non-default value for the identity field is not permitted. You either need to remove the @GeneratedValue annotation or modify the code to remove the initializer processing.
大意就是说执行merge()方法的时候我们设的值和@GeneratedValue自增的值有冲突,这明显只是EntityManager.persist()才会有的问题,EntityManager.merge()是合并的意思,在Hibernate中如果包含则合并,然而openJPA并没有这样做,不知道Apache组织理解错了游离态、瞬态、持久态的概念,还是故意要这样做的,貌似这是一个Bug,可以在http://issues.apache.org/jira/browse/OPENJPA-2074中看到。
另一方面,openJPA在Spring支持中貌似不够好,openJPA最新版本也只支持到Java EE6,一些Java EE7特性无法在Spring中显现。