1、JPA简介
JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。由SUN(已被oracle公司收购)提出,希望整合ORM技术,实现统一。JPA由EJB 3.0软件专家组开发,作为JSR-220实现的一部分。但它不囿于EJB 3.0,你可以在Web应用、甚至桌面应用中使用。JPA的宗旨是为POJO提供持久化标准规范。现在Hibernate、TopLink 已经OpenJPA都已经实现了这一规范。
2、实现
这里所用到的实现是hibernate,下载地址是http://www.hibernate.org/downloads。下载好hibernate之后新建一个Pava Project,添加如下的jar包依赖。
数据库使用的是mysql,添加依赖mysql的驱动,mysql-connector-java-5.1.18-bin.jar
准备工作完成。
1)、新建Person类,并把这个类放在com.test.bean这个包中,我们使用annotation的方式对实体bean进行配置。Person类代码如下:
package com.test.bean; import java.util.Date; import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Lob; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; enum Gender { MAN, WOMEN } @Entity @Table(name = "person") public class Person {// 表名根据实体名称取名 // @Id private Integer id;// 字段 private String name; private Date birthday;// 1987-12-10 private Gender gender = Gender.MAN; private String info; private Byte[] file; private String imagepath;// 不希望被持久化 public Person() { } public Person(String name) { this.name = name; } @Id @GeneratedValue // strategy = GenerationType.AUTO默认值 public Integer getId() {// 属性的名称这里由get和set方法决定的,Id, return id; } public void setId(Integer id) { this.id = id; } @Column(length = 10, nullable = false, name = "personName") public String getName() {// 对于名字最长的 return name; } public void setName(String name) { this.name = name; } @Temporal(TemporalType.DATE) public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } // 枚举类型 // @Enumerated(EnumType.ORDINAL)//数据库保存索引值,从0开始,建议保存String类型 @Enumerated(EnumType.STRING) @Column(length = 5, nullable = false) public Gender getGender() { return gender; } public void setGender(Gender gender) { this.gender = gender; } // 大文本类型 @Lob public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } // 文件字节数组 @Lob @Basic(fetch = FetchType.LAZY) // 延迟加载,若文件太大,使用的时候加载,否则浪费内存,推荐若超过M就该使用延迟加载 public Byte[] getFile() { return file; } public void setFile(Byte[] file) { this.file = file; } // 不与数据库表中的字段做映射 @Transient public String getImagepath() { return imagepath; } public void setImagepath(String imagepath) { this.imagepath = imagepath; } }
2)、在src下新建一个名称为META-INF的package,并在META-INF下新建一个名称为persistence.xml的xml文件。persistence.xml文件的内容如下:
<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="jpatest" transaction-type="RESOURCE_LOCAL">
<!-- JTA事务只能运行在J2EE的环境中,即EJB容器中和Web容器中;而在J2SE环境中只能使用RESOURCE_LOCAL管理事务。 --> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" /><!-- 数据库数据库方言 --> <property name="hibernate.hbm2ddl.auto" value="update" /><!-- 数据库用户名 --> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" /><!-- 数据库驱动 --> <property name="hibernate.connection.username" value="root" /><!-- 数据库用户名 --> <property name="hibernate.connection.password" value="123456" /><!-- 数据库密码 --> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpatest?useUnicode=true&characterEncoding=UTF-8" /><!-- 数据库连接url --> <property name="hibernate.show_sql" value="true"></property><!-- 操作时显示sql语句 --> <property name="Hibernate.format_sql" value="true"></property><!-- 将显示的sql语句格式化 --> </properties> </persistence-unit> </persistence>
3)、生成数据库表
此时连接的数据库是jpatest,这个数据库需要我们先在mysql中建好,jpa不会给我们自动生成数据库,只能自动帮我们生成表。
@Test public void testSave() {
// -->SessionFactory -->session -->begin事务
EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpatest");//jpatest为persistence.xml里面persistence-unit的name值
// 得到SessionFactory,EntityManagerFactory对象的时候,就会创建表
EntityManager manager = factory.createEntityManager();
manager.close();
factory.close();
}
通过这行代码我们可以为jpatest这个数据库生成表,表结构如下:
CREATE TABLE `person` ( `id` int(11) NOT NULL AUTO_INCREMENT, `birthday` date DEFAULT NULL, `file` longblob, `gender` varchar(5) NOT NULL, `info` longtext, `personName` varchar(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
4)、保存数据
@Test public void testSave() { EntityManagerFactory factory = Persistence .createEntityManagerFactory("jpatest"); manager.getTransaction().begin();// 开始事务
// session.save() --> persist();
Person person = new Person("张三");
person.setBirthday(new Date());
person.setGender(Gender.MAN);
person.setInfo("zhang san info");
byte[] file = "张三是个好孩子".getBytes();
person.setFile(file);
manager.persist(person);
manager.getTransaction().commit();//提交事务
manager.close();
factory.close();
}
5)、查询数据
@Test public void testQuery() {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpatest");
EntityManager manager = factory.createEntityManager();
// ====================方式一====================== // Person实体的名称,o是别名,jpa中必须使用select p Query query = manager.createQuery("select p from Person p where p.id=?1"); query.setParameter(1, 1); Person person = (Person) query.getSingleResult();// 该记录必须存在,否则会出错
System.out.println(person);
// ====================方式二======================
Person person2 = manager.find(Person.class, 1);// find使用了泛型,所有无需转换,相当于hibernate中的get方法
System.out.println(person2);
// ====================方式三======================
// load延迟初始化,不会立刻调用,只是返回一个代理对象,当对代理对象的属性进行访问的时候,才会从数据库中得到这条记录,不然不会发生数据的加载行为。EntityManager必须没有关闭 Person person3 = manager.getReference(Person.class, 1);
System.out.println(person3);// 若没有id为2的记录,此时,才会出现异常
manager.close();
factory.close();
}
如果执行Person person = manager.getReference(Person.class, 1);之后用来一分钟处理,数据中的person记录已被其他人修改. 此时若再执行manager.find()方法仍无法获取最新修改的person对象,它会从实体管理器EntityManager中的实体bean的缓存中获取原先查询到的对象。此时需要调用manager.refresh(person)这个方法,调用之后会重新到数据库中去查询最新的数据。
6)、修改数据
@Test public void testUpdatePerson() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpatest"); EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin();
// ====================方式一=====================
// Person实体的名称,o是别名,jpa中必须使用select p
manager.getTransaction().begin();
Query query = manager.createQuery("update Person p set p.name=:name where p.id=:id");
query.setParameter("name", "李四xxx");
query.setParameter("id", 3);
query.executeUpdate();
manager.getTransaction().commit();
// ====================方式二=====================
manager.getTransaction().begin();
Person person = manager.find(Person.class, 1);
person.setName("李四");// 与事务关联,处于托管状态,可更新
manager.getTransaction().commit();
// ====================方式二=====================
manager.getTransaction().begin();
Person person = manager.find(Person.class, 1);
manager.clear();// 把实体管理器中的所有实体变成游离状态,
person.setName("李四33");// 此时person为游离状态,无法同步到数据库
manager.merge(person);// 把实体在游离状态的更新同步到数据库
manager.getTransaction().commit();
manager.close(); factory.close(); // new 新建状态 new Person("张三") // managed 托管状态 Person person = manager.find(Person.class, 1); // 游离状体(脱管) // 删除状态 }
6)、删除数据
@Test public void testdeleteQuery() { EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpatest"); EntityManager manager = factory.createEntityManager();
// ====================方式一===================== manager.getTransaction().begin(); // Person实体的名称,o是别名,jpa中必须使用select p Query query = manager.createQuery("delete from Person p where p.id=?1"); query.setParameter(1, 1); query.executeUpdate(); manager.getTransaction().commit();
// ====================方式二===================== manager.getTransaction().begin(); Person person = manager.find(Person.class, 1); manager.remove(person);// 必须托管状态 manager.getTransaction().commit(); manager.close(); factory.close(); }