环境:Eclipse Jpa2.0 jdk1.7 tomcat7
1、在eclipse中 一个jpa项目
创建完成后,可以看到建好的项目
Persistence.xml是jpa项目的全局配置文件
2、添加项目需要的jar包
antlr-2.7.7.jar
dom4j-1.6.1.jar
ehcache-core-2.4.3.jar
hibernate-commons-annotations-4.0.2.Final.jar
hibernate-core-4.2.4.Final.jar
hibernate-ehcache-4.2.4.Final.jar
hibernate-entitymanager-4.2.4.Final.jar
hibernate-jpa-2.0-api-1.0.1.Final.jar
javassist-3.15.0-GA.jar
jboss-logging-3.1.0.GA.jar
jboss-transaction-api_1.1_spec-1.0.1.Final.jar
mysql-connector-java-5.1.7-bin.jar
ojdbc6.jar
slf4j-api-1.6.1.jar
这里添加了两个数据库的驱动包,不是必须的,根据自己连接的数据库来添加不同的驱动包
3、在src目录下创建bean目录,用于存放于数据库关联的实体类(本案例创建了三个实体类做演示,分别是:Account、Emp4、Dept6)
实体类可以手动创建,也可以通过工具生成
如果是jpa项目,可以通过在项目右键,选择JPA Tools选项,里面可以反向生成实体类
右侧红线框中,第一个是根据实体构建表,下面那个是根据表构建实体类
实体类注意事项:
如果单表操作无所谓,但是一旦涉及到多表操作,就会出现很多问题:
1) 数据类型要用Integer这种包装类型,不要用基本数据类型(不然会出现在数据库中生成关联对象列)
2) 所有注解不要放在属性上,要放在get方法上(不然也会出现在数据库中生成关联对象列)
3) 如果是自己新建的实体类,添加@Entity注解后,会出错,需要在persistence.xml中引用此类才行(引用方式在下面会的persistence.xml文件中会介绍);并且还要加上@ID注解,不然也会编译错误
4、配置persistence.xml,完整的xml配置如下:
<?xmlversion="1.0"encoding="UTF-8"?>
<persistenceversion="2.0"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/persistencehttp://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unitname="jpa_test1">
<!--
配置使用什么 ORM产品来作为 JPA的实现
1. 实际上配置的是 javax.persistence.spi.PersistenceProvider接口的实现类
2. 若 JPA项目中只有一个 JPA的实现产品,则也可以不配置该节点.
-->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- 加入持久化类 -->
<class>jpa_test1.Account</class>
<class>jpa_test1.Emp4</class>
<class>jpa_test1.Dept6</class>
<!--
配置二级缓存的策略(不是必须)
ALL:所有的实体类都被缓存
NONE:所有的实体类都不被缓存.
ENABLE_SELECTIVE:标识 @Cacheable(true)注解的实体类将被缓存
DISABLE_SELECTIVE:缓存除标识 @Cacheable(false)以外的所有实体类
UNSPECIFIED:默认值,JPA产品默认值将被使用
-->
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<!-- 连接数据库的基本信息 -->
<propertyname="javax.persistence.jdbc.driver"value="oracle.jdbc.OracleDriver"/>
<propertyname="javax.persistence.jdbc.url"value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<propertyname="javax.persistence.jdbc.user"value="scott"/>
<propertyname="javax.persistence.jdbc.password"value="tiger"/>
<!-- 配置 JPA实现产品的基本属性.配置 hibernate的基本属性(不是必须) -->
<propertyname="hibernate.format_sql"value="true"/>
<propertyname="hibernate.show_sql"value="true"/>
<propertyname="hibernate.hbm2ddl.auto"value="update"/>
<!-- 二级缓存相关(不是必须) -->
<propertyname="hibernate.cache.use_second_level_cache"value="true"/>
<propertyname="hibernate.cache.region.factory_class"value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
<propertyname="hibernate.cache.use_query_cache"value="true"/>
</properties>
</persistence-unit>
</persistence>
5、创建一个test包,包中创建一个测试类,测试单表操作,代码如下:
public class MyTest {
public static void main(String[] args) {
String pname="jpa_test1";
//1、EntityManagerFactory相当于hibernate的sessionFactory
//有两种创建方法,第一种是直接传到persistence.xml中persistence-unit标签的名称
EntityManagerFactory facotry=Persistence.createEntityManagerFactory(pname);
//另一种是不管可以传递名字,还可以传递一些参数,如下面show_sql的参数来设置连接的配置
/*Map map=new HashMap();
map.put("hibernate.show_sql", false);
EntityManagerFactory facotry=Persistence.createEntityManagerFactory(pname);*/
//2、EntityManager相当于hibernate的session
EntityManager manager=facotry.createEntityManager();
//3、开启事务
EntityTransaction tran=manager.getTransaction();
tran.begin();
//4、进行持久化操作
//插入,相当于hibernate的save(和hibernate的 save方法的不同之处:若对象有 id, 则不能执行 insert操作,而会抛出异常. )
/*Account acc=newAccount();
acc.setUsername("jpatest1");
acc.setPassword("123");
manager.persist(acc);
//保存完后可以获取保存成功的ID
System.out.println(acc.getAid());
*/
//find查询,相当于hibernate的get方法
/*Account acc=manager.find(Account.class,1);
System.out.println(acc.getUsername());*/
//getReference,相当于hibernate的load方法(getReference只有使用查询出来的对象才会发送SQL,而get执行查询就立即发送SQL查询)
Account acc=manager.getReference(Account.class, 1);
System.out.println(acc.getUsername());
//5、提交事务
tran.commit();
//6、关闭EntityManager
manager.close();
//7、关闭EntityManagerFactory
facotry.close();
}
}
-------------到此为止单表的jpa操作完毕------------
6、单向多对一
1) 在Emp6中,新建一个private Dept6 dept; 并且提供get/set和注解,配置如下:
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="deptid")
publicDept6 getDept() {
returndept;
}
publicvoid setDept(Dept6 dept) {
this.dept= dept;
}
2) 在测试类中进行测试
Dept6 dept=new Dept6();
dept.setDeptname("jpa1");
dept.setLoc("1111");
Emp4 emp1=newEmp4();
emp1.setEname("11");
emp1.setDept(dept);
Emp4 emp2=new Emp4();
emp2.setEname("222");
emp2.setDept(dept);
manager.persist(dept);//先保存一方(如果数据库已经有一方数据,需要做多对一的添加,也可以直接创建一个部门对象,设置一个id值,不一定非要先保存dept,才能让员工获得一方dept对象,比如可以像横线下面那段代码写法)
manager.persist(emp1);//再保存多方
manager.persist(emp2);
Dept6 dept=new Dept6();
dept.setId(5650);
Emp4 emp1=new Emp4();
emp1.setEname("11");
emp1.setDept(dept);
Emp4 emp2=new Emp4();
emp2.setEname("222");
emp2.setDept(dept);
manager.persist(emp1);
manager.persist(emp2);
6、单向一对多
1) 在Dept6中,添加如下集合,存放关联的员工:
private Set<Emp4> emps=new HashSet<Emp4>();
并生成get/set和注解,配置如下:
//注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 属性, 则 @OneToMany 端就不能再使用 @JoinColumn 属性了.
@OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
@JoinColumn(name="deptid")
public Set<Emp4>getEmps() {
returnemps;
}
public voidsetEmps(Set<Emp4> emps) {
this.emps =emps;
}
注意: 定义的set集合需要new,并且需要指定泛型
2) 在测试类中进行测试,代码如下:
Dept6 dept=new Dept6();
dept.setDeptname("xxx");
Emp4 emp1=new Emp4();
emp1.setEname("11");
Emp4 emp2=new Emp4();
emp2.setEname("222");
dept.getEmps().add(emp1);
dept.getEmps().add(emp2);
manager.persist(dept);
6、JPQL查询
1) 基础jpql
String jpql = "FROM Customer c WHERE c.age > ?";
Query query= entityManager.createQuery(jpql);
//占位符的索引是从 1 开始
query.setParameter(1,1);
List<Customer>customers = query.getResultList();
System.out.println(customers.size());
2) 如果只想查询部分列,那么集合将会存放数组
如果查询部分列,不想集合存放数组,那么需要给实体提供一个对应的构造函数,并如下查询:
Stringjpql = "SELECT new Customer(c.lastName, c.age) FROM Customer c WHERE c.id> ?";
List result=
entityManager.createQuery(jpql).setParameter(1, 1).getResultList();
System.out.println(result);
3) 也可以通过createNamedQuery查询实体类中已经写好的jpql
@NamedQuery(name="testNamedQuery", query="FROM Customer cWHERE c.id = ?")//这里eclipse可能会显示错误,但是不影响运行,也可以写成select c FROM Customer c WHERE c.id = ?
@Table(name="JPA_CUTOMERS")
@Entity
publicclass Customer {
Queryquery =
entityManager.createNamedQuery("testNamedQuery").setParameter(1,3);
Customercustomer = (Customer) query.getSingleResult();
System.out.println(customer);
4) 也可以使用sql语句查询:
String sql = "SELECT age FROM jpa_cutomers WHERE id = ?";
Query query= entityManager.createNativeQuery(sql).setParameter(1, 3);
Objectresult = query.getSingleResult();
System.out.println(result);
5) 使用 hibernate 的查询缓存
在每次查询后面跟上.setHint(QueryHints.HINT_CACHEABLE, true);
如:
第一次查询:Query query =
entityManager.createQuery(jpql)
.setHint(QueryHints.HINT_CACHEABLE, true);
第二次查询:query =
entityManager.createQuery(jpql)
.setHint(QueryHints.HINT_CACHEABLE, true);
6) 查询时也可以使用OrderBy、GroupBy、关联查询、子查询,如:
OrderBy:
String jpql = "FROM Customer c WHERE c.age > ? ORDER BY c.ageDESC";
GroupBy:
String jpql = "SELECT o.customer FROM Order o "
+"GROUP BY o.customer "
+"HAVING count(o.id) >= 2";
关联查询:
Stringjpql = "FROM Customer c LEFT OUTER JOIN FETCH c.orders WHERE c.id = ?";
子查询:
String jpql = "SELECT o FROM Order o "
+ "WHERE o.customer = (SELECT c FROM Customer c WHERE c.lastName =?)";
7) 使用 jpql 自带的函数
String jpql = "SELECT lower(c.email) FROM Customer c";
8) 可以使用 JPQL 完成 UPDATE 和 DELETE 操作
String jpql = "UPDATE Customer c SET c.lastName = ? WHERE c.id =?";