框架学习之JPA(一)
JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。
学习视频:尚硅谷框架jpa学习(有兴趣的同学留言邮箱)
使用软件:eclipse
Java版本:jdk8
目录:
一、JPA_hello world
1.创建一个jpa项目,导入jar包
2.配置persistence.Xml文件
3.创建一个Customer类
4.Main类进行持久化操作
二、JPA_基本注解
1.基本的六个注解
@Entity
@Table
@Id
@GeneratedValue
@Column
@Basic
2.@Transient
3.@Temporal
4.用Table生成主键
三、JPA_API
1.Persistence
2.EntityManagerFactory
3.entityManager
4.EntityTransaction
一、JPA_hello world
1.创建一个jpa项目,导入jar包
l Hibernate包
l Jpa整合包
l Mysql连接包
2.配置persistence.Xml文件
<persistence-unit name="SGG-jpa" transaction-type="RESOURCE_LOCAL"> <!-- 配置使用什么 ORM 产品来作为 JPA 的实现 1. 实际上配置的是 javax.persistence.spi.PersistenceProvider 接口的实现类 2. 若 JPA 项目中只有一个 JPA 的实现产品, 则也可以不配置该节点. --> <provider>org.hibernate.ejb.HibernatePersistence</provider> <!-- 添加持久化类 --> <class>hue.edu.xiong.jpa.Customer</class> <properties> <!-- 连接数据库的基本信息 --> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="admin"/> <!-- 配置JPA实现产品的基本属性,配置hibernate --> <property name="hibernate.format_sql" value="true"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.hbm2ddl.auto" value="update"/> </properties> </persistence-unit> |
3.创建一个Customer类
package hue.edu.xiong.jpa; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Table(name="JPA_CUSTOMERS") @Entity public class Customer { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Integer id; @Column(name="LAST_NAME") private String lastName; private String email; private Integer age; //get,set略,请自行补充 } |
4.Main类进行持久化操作
package hue.edu.xiong.jpa; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class Main { public static void main(String[] args) { // 1.创建EntitymanagerFactory String persistenceUnitName = "SGG-jpa"; EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName); // 2.创建Entitymanager EntityManager entityManager = entityManagerFactory.createEntityManager(); // 3.开启事务 EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); // 4.进行持久化操作 Customer customer = new Customer(); customer.setAge(12); customer.setEmail("[email protected]"); customer.setLastName("xiong"); entityManager.persist(customer); // 5.提交事务 transaction.commit(); // 6.关闭Entitymanager entityManager.close(); // 7.关闭EntitymanageFactory entityManagerFactory.close(); } } |
运行之后自动在mysql中创建了表,储存了数据,并且表结构和名称和我们声明的一样
二、JPA_基本注解
如果@Id注解放在get方法上面,默认找到其set方法然后才映射到数据库中,所有的get方法都会按照这个规则进行
如果@Id注解放在属性名上面,则默认会映射属性,无论会不会有get和set方法,所有的属性都会按照这个规则进行
注:我自己总结的规则,了能是错误的
1.基本的六个注解
@Entity
@Table
@Id
@GeneratedValue
@Column
@Basic
1)@Entity
l @Entity标注用于实体类声明语句之前,指出该java类为实体类,将映射到指定的数据库表。
2)@Table
l 当实体类与其映射的数据库表名不同名时需要使用@Table标注说明,该标注与@Entity并列使用,置于实体类声明语句之前,可写于单独语句行,也可与声明语句同行。如果不加@Table,默认表名为类名。
l @Table标注的常用选项name,用于致命数据表的表名
l @Table还有两个选项catalog和schema用于设置表所属的数据库目录或模式,通常为数据库名。uniqueConstraints选项用于设置约束条件,通常不设置。
3)@Id
l @Id标注用于声明一个实体类的属性映射为数据库的主键列。该属性通常置于属性声明语句之前,可与生命语句同行,也可以写在单独行上。
l @Id标注也可以置于属性的getter方法之前。
4)@GeneratedValue
l @GeneratedValue 用于标注主键生成策略,通过strategy属性指定。默认情况下,JPA自动选择一个最适合底层数据库的主键生成策略:SqlServer对应identity,MySQL对应auto或者increment
l 在javax.persistence.GenerationType定义了一下几种可供选择的策略:
n IDENTITY:采用数据库ID自增长的方式来自增主键字段,Oracle不支持这种方式
n AUTO:JPA自动选择合适的策略,是默认选项
n SEQUENCE:通过序列生成主键,通过@SequenceGenerator注解指定序列名,Mysql不支持这种方式
n TABLE:通过表产生主键,框架借由表模拟序列产生主键使用该策略可以使应用更易于数据库移植
5)@Basic
l @Basic表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的getXxxx()方法。默认为@Basic
l fetch:表示该属性的读取策略,有EAGER和LAZY两种,分别表示主支抓取和延迟加载,默认为EAGER。
l Optional:表示该属性是否允许为null,默认为true
6)@Column
l 当实体的属性与其映射的数据表的列名不同时需要使用,@Column注解说明,该属性通常置于实体的属性声明语句之前,还可以与@Id一起使用。
l @Column标注的column常用属性是name,用于设置映射数据库表的列名,此外,该注解还包含其他多个属性,如:unique,nullable,length等。
l @Column标注的columnDefinition属性:表示该字段在数据库中的实际类型,通常ORM框架可以根据属性类型自动判断数据库中的字段类型,但是对于Date类型仍无法确定数据库中字段类型究竟是Date,Time还是TimeStamp。此外,String的默认映射类型为VARCHAR,如果要将String类型映射到特定数据库的BLOB或者TEXT字段类型
l @Column标注也可以置于属性的getter方法之前
2.@Transient
l 表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性
l 如果一个属性并非数据库表的字段映射,就务必将其标注为@Transient否则ORM框架默认其注解为@Basic
3.@Temporal
l 在核心的Java API中没有定义Date类型的精度(temporal precision)。而在数据库中,表示Date类型的数据有DATE,TIME和TIMESTAMP三种精度(即单纯的日期,时间,或者两者兼备)。在进行属性映射时可以使用@Temporal注解来调整精度
4.用Table生成主键
通过其他的表的内容来生成主键ID,使用于所有的数据库,但是这个使用的几率很小
1)创建一个jpa_id_generators表
2)设置主键的标签(主键部分的java代码)
@Id @GeneratedValue(strategy=GenerationType.TABLE,generator="ID_GENERATOR") @TableGenerator(name="ID_GENERATOR", table="jpa_id_generators", pkColumnName="PK_NAME", pkColumnValue="CUSTOMER_ID", valueColumnName="PK_VALUE", allocationSize=100) private Integer id; |
3)生成效果
两张表的数据都会进行修改
三、JPA_API
1.Persistence
l Persistence类是用于获取EntityManagerFactory实例。该类包含一个名为createEntityManagerFactory的静态方法。
l createEntityManagerFactory方法有如下两个重载方法
n 带有一个参数的方法以及JPA配置文件persistence。Xmi中的持久化单元名为参数
n 带有两个参数的方法:前一个参数含义相同,后一个参数Map类型,用于设置JPA的相关属性,这时将忽略其他地方设置的属性。Map对象的属性名必须是JPA实现库提供商的名字空间约定的属性名
2.EntityManagerFactory
l EntityManagerFactory接口主要用来创建EntityManager实例。该接口约定了如下四个方法
n createEntityManager():用于创建实体管理器对象实例
n createEntityManager(Map map):用于创建实体管理器对象实例的重载方法,Map参数用于提供EntityManager的属性。
n isOpen():检查EntityManagerFactory是否处于打开状态。实体管理器工厂创建后一直处于打开状态,除非用close()方法将其关闭
n close():关闭EntityManagerFactory。EntityManagerFactory关闭后将释放所有资源,isOpen()方法将返回false,其他方法将不能调用,否则将导致IllegalStateException异常
3.entityManager
实体的状态:
1.新建状态:新创建的状态,尚未拥有持久性主键
2.持久化状态:已经拥有持久性主键并和持久化建立了上下文环境
3.游离状态:拥有持久化主键,但是没有与持久化建立上下文环境
4.删除状态:拥有持久化主键,已经和持久化建立上下文环境,但是从数据库中删除
l Find()
//类似于hibernate中session的get方法 @Test public void testFind() { Customer customer = entityManager.find(Customer.class, 1); System.out.println("---------------------------"); System.out.println(customer.toString()); } |
l GetReference()
//类似于hibernate中session的load方法 @Test public void testGetReference() { Customer customer = entityManager.getReference(Customer.class, 1); //这是一个代理对象,可能会出现懒加载异常,即在使用当前customer之前就把entityManager关闭,就无法进行数据库访问 System.out.println(customer.getClass().getName()); System.out.println("---------------------------"); System.out.println(customer.toString()); } |
l Persist()
//类似于hibernate中的save方法,使对象由临时状态变为持久化状态 //和hibernate的save方法的不同之处:若对象有id,则不能执行insert操作,而会抛出异常 @Test public void testPersistence() { Customer customer = new Customer(); customer.setAge(12); customer.setEmail("[email protected]"); customer.setLastName("xiong"); customer.setBirth(new Date()); customer.setCreatedTime(new Date()); entityManager.persist(customer); //可以打印Id System.out.println(customer.getId()); } |
l Remove()
//类似于hibernate的delete方法,把对象对应的记录从数据库中移除 //但注意:该方法只能移除持久化对象。二hibernate的delete方法实际上还可以移除游离对象 @Test public void testRemove() { Customer customer = entityManager.find(Customer.class, 2); entityManager.remove(customer); } |
l Merge()
//若传入的是一个游离对象, 即传入的对象有 OID. //1. 若在 EntityManager 缓存中有对应的对象 //2. JPA 会把游离对象的属性复制到查询到EntityManager 缓存中的对象中. //3. EntityManager 缓存中的对象执行 UPDATE. @Test public void testMerge4(){ Customer customer = new Customer(); customer.setAge(18); customer.setBirth(new Date()); customer.setCreatedTime(new Date()); customer.setEmail("[email protected]"); customer.setLastName("DD"); customer.setId(4); Customer customer2 = entityManager.find(Customer.class, 4); entityManager.merge(customer); System.out.println(customer == customer2); //false } //若传入的是一个游离对象, 即传入的对象有 OID. //1. 若在 EntityManager 缓存中没有该对象 //2. 若在数据库中也有对应的记录 //3. JPA 会查询对应的记录, 然后返回该记录对一个的对象, 再然后会把游离对象的属性复制到查询到的对象中. //4. 对查询到的对象执行 update 操作. @Test public void testMerge3(){ Customer customer = new Customer(); customer.setAge(18); customer.setBirth(new Date()); customer.setCreatedTime(new Date()); customer.setEmail("[email protected]"); customer.setLastName("EE"); customer.setId(4); Customer customer2 = entityManager.merge(customer); System.out.println(customer == customer2); //false } //若传入的是一个游离对象, 即传入的对象有 OID. //1. 若在 EntityManager 缓存中没有该对象 //2. 若在数据库中也没有对应的记录 //3. JPA 会创建一个新的对象, 然后把当前游离对象的属性复制到新创建的对象中 //4. 对新创建的对象执行 insert 操作. @Test public void testMerge2(){ Customer customer = new Customer(); customer.setAge(18); customer.setBirth(new Date()); customer.setCreatedTime(new Date()); customer.setEmail("[email protected]"); customer.setLastName("DD"); customer.setId(100); Customer customer2 = entityManager.merge(customer); System.out.println("customer#id:" + customer.getId()); System.out.println("customer2#id:" + customer2.getId()); } /** * 总的来说: 类似于 hibernate Session 的 saveOrUpdate 方法. */ //1. 若传入的是一个临时对象 //会创建一个新的对象, 把临时对象的属性复制到新的对象中, 然后对新的对象执行持久化操作. 所以 //新的对象中有 id, 但以前的临时对象中没有 id. @Test public void testMerge1(){ Customer customer = new Customer(); customer.setAge(18); customer.setBirth(new Date()); customer.setCreatedTime(new Date()); customer.setEmail("[email protected]"); customer.setLastName("CC"); Customer customer2 = entityManager.merge(customer); System.out.println("customer#id:" + customer.getId()); System.out.println("customer2#id:" + customer2.getId()); } |
l Flush():同步持久上下文,即将持久上下文环境所有未保存实体的状态信息保存到数据库中。
l SetFlushMode(FlushModeType flushMode):设置持久上下文换进的Flush模式。参数可以取两个枚举
n FlushModeType.AUTO为自动跟新数据库实体
n FlushModeType.COMMIT为直到提交事物时才更新数据库记录
l getFlushMode():获得持久上下文环境的Flush模式。返回FlushModeType的枚举值
l Refresh(Object entity):用数据库实体记录的值跟新实体对象的状态,即更新实例的属性值
l Clear():清除持久上下文环境,断开所有关联的实体。如果这是还有未提交的更新则会被撤销
l Contains(Object entity):判断一个实体是否属于当前持久上下文环境管理的实体
l isOpen():判断当前实体管理器是否处于的打开状态
l getTransaction():返回资源层的事务对象。EntityTransaction实例可以用于开始和提交多个事务。
l Close():关闭实体管理器,之后若调用实体管理器实例的方法或其派生的查询对象的方法都将抛出IllegalstateException异常,除了getTransaction和idOpen方法
4.EntityTransaction
l Begin():用于启动一个事务,此后的多个数据库将作为整体被提交或者撤销,若这时事务已经被启动则会抛出异常IllegalstateException
l commit():用于提交当前事务。即将事务启动以后的所有数据库更新操作持久化至数据库中
l Rollback():撤销回滚操作。即撤销事务启动以后的的所有数据库更新操作,从而不对数据库产生影响。
l setRollbackOnly():使当前事务只能被撤销
l getRollbackOnly():查看当前事务是否设置了只能撤销标志
l isActive():查看当前事务是否是活动的。