本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Hibernate 简单使用
1.在 Maven 项目中使用 Hibernate,这里省略数据库驱动与数据源的依赖坐标。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.2.Final</version>
</dependency>
2.创建配置文件 src/main/resources/META-INF/persistence.xml。
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/persistence"
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="myJpa" transaction-type="RESOURCE_LOCAL">
<description>jpa入门案例演示</description>
<class>cn.smbms.entity.Product</class>
<properties>
<!-- <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>-->
<!-- <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/smbms"/>-->
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://127.0.0.1:5432/smbms"/>
<property name="javax.persistence.jdbc.user" value="postgres"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="none"/>
</properties>
</persistence-unit>
</persistence>
3.配置与表映射的 Java Entity。
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table
public class Product implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Integer productId;
@Column
private String productName;
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
}
4.修改 persistence.xml hibernate.hbm2ddl.auto=create 设置 Hibernate 根据 Entity 配置自动建表,注意表结构创建好之后一般后续都修改 hibernate.hbm2ddl.auto 为 none。
<property name="hibernate.hbm2ddl.auto" value="create"/>
5.使用 Hibernate 进行 CRUD 测试。 插入:
@Test
public void test_01() {
// 根据 persistence.xml 中 persistence-unit=myJpa 配置创建 EntityManager 实例,
// 我们通过该 entityManager 操作数据库
EntityManager entityManager = Persistence.createEntityManagerFactory("myJpa").createEntityManager();
EntityTransaction tx = null;
try {
tx = entityManager.getTransaction();
tx.begin();
Product p = new Product();
p.setProductName("电冰箱");
entityManager.persist(p);
// int i = 1 / 0;
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
entityManager.close();
}
}
观察控制台我们发现 Hibernate 不仅创建了表结构,还插入了数据:
执行结果:
后续演示部分代码省略 EntityManager 实例的创建。
查,findById:
entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
Product product = entityManager.find(Product.class, 1);
logger.info("Product=>id:{},name:{}", product.getProductId(), product.getProductName());
entityManager.getTransaction().commit();
entityManager.close();
查,findAll:
entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
List<Product> list = entityManager.createQuery("from Product", Product.class).getResultList();
list.forEach(x -> logger.info("P=>id:{},name:{}", x.getProductId(), x.getProductName()));
entityManager.getTransaction().commit();
entityManager.close();
改:
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
// 封装了对 Persistence.createEntityManagerFactory("myJpa") 的调用
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
Product p = new Product();
p.setProductId(3);
p.setProductName("电冰箱");
//修改方法
entityManager.merge(p);
// int i = 1/0;
tx.commit();
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx); // 判空后调用 tx 的 rollback 方法
} finally {
JPAUtil.close(entityManager); // 判空后调用 entityManager 的 close 方法
}
改(Java 对象与数据库数据行关联,对象的修改直接同步到数据库):
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
Product p = entityManager.find(Product.class, 3);//p从这之后就会变成持久化对象
p.setProductName("空调");
tx.commit();
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx);
} finally {
JPAUtil.close(entityManager);
}
删:
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
Product p = entityManager.find(Product.class, 3);//p从这之后就会变成持久化对象
entityManager.remove(p);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx);
} finally {
JPAUtil.close(entityManager);
}
查,立即加载:
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
//find()为立即加载 SQL语句 get()
Product p = entityManager.find(Product.class, 2);//p从这之后就会变成持久化对象
//没有使用p对象
tx.commit();
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx);
} finally {
JPAUtil.close(entityManager);
}
查,延迟加载:
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
//getReference为延迟加载 SQL语句 load()
//返回来的是一个 代理模式生成的代理对象 该代理对象中只有主键 其他的并没有
Product p = entityManager.getReference(Product.class, 1);//p从这之后就会变成持久化对象
//使用主键
System.out.println(p.getProductId());
Thread.sleep(1000); // sleep 之前 SQL 并未执行
System.out.println(p.getProductName());
//没有使用p对象
tx.commit();
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx);
} finally {
JPAUtil.close(entityManager);
}
查,缓存:
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
//find()为立即加载 SQL语句 get()
Product p = entityManager.find(Product.class, 1);//p从这之后就会变成持久化对象
Product p2 = entityManager.find(Product.class, 1);//p从这之后就会变成持久化对象
System.out.println(p == p2);// true
//没有使用p对象
tx.commit();
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx);
} finally {
JPAUtil.close(entityManager);
}
查,JPQL:
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
String jpql = "from Product";
List<Product> resultList = entityManager.createQuery(jpql, Product.class).getResultList();
resultList.forEach(x -> logger.info("P=>id:{},name:{}", x.getProductId(), x.getProductName()));
//没有使用p对象
tx.commit();
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx);
} finally {
JPAUtil.close(entityManager);
}
查,JPSQL 模糊查询(参数位置):
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
// 根据产品名 模糊查询产品信息 使用参数位置绑定的方式 传递参数
// 参数命名方式
String jpql = "from Product where productName like concat('%',?0,'%')";
List<Product> resultList = entityManager.createQuery(jpql, Product.class)
.setParameter(0, "手").getResultList();
resultList.forEach(x -> logger.info("P=>id:{},name:{}", x.getProductId(), x.getProductName()));
tx.commit(); // 没有使用 p 对象
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx);
} finally {
JPAUtil.close(entityManager);
}
查,JPSQL 模糊查询(参数别名):
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
// 根据产品名 模糊查询产品信息 使用参数命名方式 绑定参数
String jpql = "from Product where productName like concat('%',:name,'%')";
List<Product> resultList = entityManager.createQuery(jpql, Product.class)
.setParameter("name", "手").getResultList();
resultList.forEach(x -> logger.info("P=>id:{},name:{}", x.getProductId(), x.getProductName()));
tx.commit(); // 没有使用p对象
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx);
} finally {
JPAUtil.close(entityManager);
}
查,JPQL 统计:
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
//根据产品名 模糊查询产品信息 使用参数命名方式 绑定参数
String jpql = "select count(*) from Product";
//uniqueResult():统计查询用的
Long resultList = ((Long) entityManager.createQuery(jpql).getSingleResult());
System.out.println(resultList.getClass());//int long
System.out.println(resultList.intValue());//int long
//没有使用p对象
tx.commit();
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx);
} finally {
JPAUtil.close(entityManager);
}
查,JPQL 分页查询:
EntityManager entityManager = null;
EntityTransaction tx = null;
try {
entityManager = JPAUtil.getEntityManager();
tx = entityManager.getTransaction();
tx.begin();
//根据产品名 模糊查询产品信息 使用参数命名方式 绑定参数
String jpql = "select count(*) from Product";
//uniqueResult():统计查询用的
Long resultList = ((Long) entityManager.createQuery(jpql).getSingleResult());
int totalCount = resultList.intValue();
System.out.println("总记录数:" + totalCount);
int pageNo = 1;
int pageSize = 2;
//计算总页数
int totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1;
System.out.println("总页数是:" + totalPage);
//分页
String jpqlPage = "from Product order by productId desc";
List<Product> productList = entityManager.createQuery(jpqlPage, Product.class)
.setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).getResultList();
for (Product product : productList) {
System.out.println(product);
}
tx.commit(); // 没有使用p对象
} catch (Exception e) {
e.printStackTrace();
JPAUtil.rollback(tx);
} finally {
JPAUtil.close(entityManager);
}
Hibernate 的工作原理
1.在我们给项目中引入 hibernate-entitymanager 包后,classpath 下将多出一个与 Hibernate 有关的 Java SPI 文件,其指向了 Java javax.persistence.spi.PersistenceProvider 接口的 java persistence 规范接口的实现 org.hibernate.jpa.HibernatePersistenceProvider。
2.我们回顾我们 EntityManager 实例的创建:
EntityManager entityManager = Persistence.createEntityManagerFactory("myJpa").createEntityManager(),其原理是调用 javax.persistence.Persistence 的静态方法 createEntityManagerFactory。
createEntityManagerFactory 通过 ServiceLoader.load 加载 Classpath 下 hibernate-core-5.4.2.Final.jar 包中的 SPI 文件,最终拿到 Hibernate 实现的 java persistence org.hibernate.jpa.HibernatePersistenceProvider。
3.HibernatePersistenceProvider 可对项目中 src/main/resources 下 META-INF/persistence.xml 的 Hibernate 配置文件的解析。其解析 persistence-unit 下对 @Entity 与数据库连接配置,并完成 Java Entity 与数据库表之间的映射。最终构造出实例 EntityManager 供我们在 Java 程序中对数据库进行全自动的 orm 操作。