文章目录
测试项目见本地jpademo。
别人写的快速入门资料:https://www.kuangstudy.com/bbs/1370755259508580354
数据库 Hibernate-JPA
JPA懒到不想写sql为此而产生的接口,是参照ORM关系映射思想由用java实现的接口。缺点是不写sql容易退化,适用于单表查询,面对复杂多表查询就没啥用了。
mybatis对复杂的多表查询也有较好支持,可以写sql,特点是mapper接口和mapper.xml实现之间的映射很神奇,以及查询得到的结果映射给对象或者map等集合也很神奇。
mybatis-plus集合了jpa的特性且保留了mybaits特性,针对简单的查询也无需写sql,用代码形式完成对数据库查询。
考虑到仅仅是脚手架分成了用户管理,权限管理,角色管理,每个表都需要单独使用,且后续开发中不需要了解也不太需要维护脚手架因此考虑使用jpa。
JPA和Hibernate和ORM区别
ORM对象关系映射,java对象到关系表之间的映射。JDBC是最原生的ORM思想框架,不管是Hibernate,JPA,mybaits都是常见的ORM思想框架底层最终都是对JDBC的调用。
ORM(关系映射思想)—>JPA(java参照ORM写的接口规范)---->JDBC(最原生的实现ORM的框架)----->Hibernate(轻量封装JDBC)
java中实现实体类持久化存到数据库的包
import javax.persistence.*;//将实体类 持久化到数据库中 针对jpa规范使用的。
JPA操作的数据库流程
- 加载配置文件 创建实体类管理器工厂factory=Persistence.createEntityManagerFactory(“myJpa”)
- 工厂生成 实体类管理器 entityManager=factory.createEntityManager()
- 实体类管理器得到事务对象
- 开启事务
- 通过实体类管理器完成增删改查
- 提交事务
- 释放资源(实体类管理器和工厂资源释放)
通过Persistence 持久化 API先加载jpa配置文件,配置文件内容包括 jpa实现的方式(如Hibernate方式),数据库连接配置,表生成策略(update none create)。当然使用springboot自动化装配,自动配置JpaProperties中的属性即可。
persistence API对象说明
persistence是java当中实现实体类对象持久化存储到数据库的API。包含实体类管理器工厂,实体类管理器,事务等对象,从而操作数据库。其中实体类管理器entityManager是真正和数据库打交道的对象,通过persist,remove,merge,find方法实现增删改查。
@Test
public void testSave() {
//1.加载配置文件 创建实体类管理器工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory ("myJpa");
//2.工厂生成实体类管理器 有很多方法操作数据库 presist保存 merge更新 remove删除 find查询
EntityManager entityManager = factory.createEntityManager ();
//3.得到事务对象
EntityTransaction tn = entityManager.getTransaction ();
tn.begin ();//开启事务
//4.完成增删改查CRUD
Customer customer = new Customer ();
customer.setCustName ("javachuan");
customer.setCustIndustry ("test jpa2");
//5.保存
entityManager.persist (customer);
//6.提交事务
tn.commit ();
//7.释放资源
entityManager.close ();
factory.close ();
}
JPA增删改查案例
配置文件persistence.xml ,hibernate相关的配置,包括数据库连接,表生成策略等。
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<!--需要配置persistence-unit节点
持久化单元:
name:持久化单元名称
transaction-type:事务管理的方式
JTA:分布式事务管理
RESOURCE_LOCAL:本地事务管理
-->
<persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
<!--jpa的实现方式 采用hibernate -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!--可选配置:配置jpa实现方的配置信息-->
<properties>
<!-- 数据库信息
用户名,javax.persistence.jdbc.user
密码, javax.persistence.jdbc.password
驱动, javax.persistence.jdbc.driver
数据库地址 javax.persistence.jdbc.url
-->
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpademo"/>
<!--配置jpa实现方(hibernate)的配置信息
显示sql : false|true
自动创建数据库表 : hibernate.hbm2ddl.auto
create : 程序运行时创建数据库表(如果有表,先删除表再创建)
update :程序运行时创建表(如果有表,不会创建表)
none :不会创建表
-->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
</persistence-unit>
</persistence>
Customer对象
package com.zhangchuan.jpa.entity;
import javax.persistence.*; //持久化实体类到数据库中, 针对open jpa实现
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* @Description 客户实体类
*
* * 客户的实体类
* * 配置映射关系
* *
* *
* * 1.实体类和表的映射关系
* * @Entity:声明实体类
* * @Table : 配置实体类和表的映射关系
* * name : 配置数据库表的名称
* * 2.实体类中属性和表中字段的映射关系
*
*
* @Author java川
* @Date 2021-09-18-15:12
*/
@Entity
@Table(name = "cst_customer")
public class Customer {
/**
* @Id:声明主键的配置
* @GeneratedValue:配置主键的生成策略
* strategy
* GenerationType.IDENTITY :自增,mysql
* * 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增)
* GenerationType.SEQUENCE : 序列,oracle
* * 底层数据库必须支持序列
* GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增
* GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略
* @Column:配置属性和字段的映射关系
* name:数据库表中字段的名称
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cust_id")
private Long custId; //客户的主键
@Column(name = "cust_name")
private String custName;//客户名称
@Column(name="cust_source")
private String custSource;//客户来源
@Column(name="cust_level")
private String custLevel;//客户级别
@Column(name="cust_industry")
private String custIndustry;//客户所属行业
@Column(name="cust_phone")
private String custPhone;//客户的联系方式
@Column(name="cust_address")
private String custAddress;//客户地址
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
@Override
public String toString() {
return "Customer{" +
"custId=" + custId +
", custName='" + custName + '\'' +
", custSource='" + custSource + '\'' +
", custLevel='" + custLevel + '\'' +
", custIndustry='" + custIndustry + '\'' +
", custPhone='" + custPhone + '\'' +
", custAddress='" + custAddress + '\'' +
'}';
}
}
因为每次都需要获取一个实体类管理器工厂和管理器对象,将其抽象出来进行封装JPAUtils,减少资源消耗。
package com.zhangchuan.jpa.utils;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
/**
* @Description jpa工具类
* @Author java川
* @Date 2021-09-18-16:29
*/
public class JPAUtils {
private static EntityManagerFactory factory;
static {
//1.加载配置文件 创建实体类管理器工厂
factory = Persistence.createEntityManagerFactory ("myJpa");
}
/*
* @description:
* 到实体类管理器
* @param
* @author java川
* @date 2021/9/18 16:35
* @return
*/
public static EntityManager getEntityManager() {
//2.工厂生成实体类管理器
EntityManager entityManager = factory.createEntityManager ();
return entityManager;
}
/*
* @description:
* 得到事务对象
* @param
* @author java川
* @date 2021/9/18 16:46
* @return
*/
public static EntityTransaction getTransaction() {
//2.工厂生成实体类管理器
EntityTransaction tx = getEntityManager ().getTransaction ();
return tx;
}
/*
* @description:
* 释放实体类管理器,实体类管理器工厂资源
* @param
* @author java川
* @date 2021/9/18 16:37
* @return
*/
public static void close(EntityManager manager) {
manager.close ();
}
}
根据id查询用户EntityManager.find(class,primarykey)
/*
* @description:
* 根据id查询用户
* @param
* @author java川
* @date 2021/9/18 16:40
* @return
*/
@Test
public void testFind() {
//得到实体类对象
EntityManager em = JPAUtils.getEntityManager ();
//开启事务
EntityTransaction tx = JPAUtils.getTransaction ();
tx.begin ();
//增删改查 根据id查询用户
Customer customer = em.find (Customer.class, 1l);//立即加载的方式
//懒加载的方式查询
// Customer customer=em.getReference (Customer.class, 1l);
System.out.println ("customer = " + customer);
//提交事务
tx.commit ();
//资源关闭
em.close ();
}
Customer customer = em.find (Customer.class, 1l);以上查询用户采用立即加载方式,**还有延迟加载方式em.getReference (Customer.class, 1l);**也就是不会立刻发送sql语句查询,类比jdbc中的预编译(?),PrepareStatement方式。只有等到调用customer对象的时候才真正执行sql,也就是 System.out.println ("customer = " + customer)的时候才会发送sql执行得到结果。
删除对象
需要先查询得到该对象后删除。
EntityManager.remove(EntityObject)
/*
* @description:
* 删除对象
* @param
* @author java川
* @date 2021/9/18 17:07
* @return
*/
@Test
public void testRemove() {
//得到实体类对象
EntityManager em = JPAUtils.getEntityManager ();
//开启事务
EntityTransaction tx = JPAUtils.getTransaction ();
tx.begin();
//删除用户
Customer customer = em.find (Customer.class, 1l);
em.remove (customer);
//提交事务
tx.commit ();
//资源关闭
em.close ();
}
Jpql复杂sql查询语言
Java persistence sql language ,面向java对象的查询语言,JQPL操作的对象是实体对象,对象属性。SQL是面向关系数据库的查询语言,因此SQL操作的对象是数据表、数据列。
jpql语句的语法规则:sql中的表 对应为 对象,sql语句中的列字段 对应对象的属性,其余关键字同样适用jpql。
//面向对象的JPQL语句
select * from Customer where custAddress like ? group by custName //对Customer实体对象查询,按照Customer对象的custAddress属性查询并按照Customer对象属性custName属性分组。
SQL(Structured Query Language)是关系数据库查询语言。from后面跟的是“表名”,where后用“**表中字段”**做条件
//原生的SQL语句
select * from cst_customer where cust_address like ? group by cust_name //对cst_customer表执行查询,按照表中cust_address数据列查询,按照数据库cust_name分组。
JPQL语句支持两种方式的参数定义方式: 命名参数和位置参数。在同一个查询语句中只允许使用一种参数定义方式。
String jpqlSql="from Customer where custAddress like ? group by custName";
//获得query的对象
Query query = em.createQuery (jpqlSql);
//ii:对占位符参数赋值
query.setParameter (1, "%beijing");
jpql步骤
与原本的jpa新增的就是得到实体类管理器EntityManager后**调用createQuery(String jpql)**方法。
jpql步骤:
* 1.得到实体类管理器对象工厂
* 2.得到实体类管理器entityManager
* 3.entityManager.getTransaction.begin() 开启事务
* 4.根据sql写jpql语句
5.entityManager.createQuery(String jpql)得到查询对象query
* 6.给jpql语句中的占位符设置参数 query.setParamter(position,parameter);
* 7.执行jpql封装到对象 query.getResultList()
* 8.关闭事务 和关闭资源
*
jpql的增删改查
package com.zhangchuan.test;
import com.zhangchuan.jpa.utils.JPAUtils;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import java.util.List;
/**
* @Description jpql java复杂语言查询语言
*
* jpql语句的语法规则:sql中的表 对应为 对象,其余不变
*
* jpql步骤:
* 1.得到实体类管理器对象工厂
* 2.得到实体类管理器entityManager
* 3.entityManager.getTransaction.begin() 开启事务
* 4.根据sql写jpql语句
* 5.entityManager.createQuery(String jpql)得到查询对象query
* 6.给jpql语句中的占位符设置参数 query.setParamter(position,parameter);
* 7.执行jpql封装到对象 query.getResultList()
* 8.关闭事务 和关闭资源
*
* @Author java川
* @Date 2021-09-23-16:19
*/
public class JpqlTest {
/*
* @description:
* 查询全部
* sql: SELECT * FROM cst_customer
*
* @param
* @author java川
* @date 2021/9/23 17:05
* @return
*/
@Test
public void testFindAll() {
//得到实体类对象
EntityManager em = JPAUtils.getEntityManager ();
//开启事务
EntityTransaction tx = em.getTransaction ();
tx.begin ();
//sql
String jpqlSql="from com.zhangchuan.jpa.entity.Customer";
//query对象执行jpql的对象
Query query = em.createQuery (jpqlSql);
//得到全部数据
List resultList = query.getResultList ();
for (Object o : resultList) {
System.out.println (o+" ");
}
//提交事务
tx.commit ();
em.close ();
}
/*
* @description:
* 倒序排序
* sql:SELECT* FROM cst_customer ORDER BY cust_id DESC
* jpql: from Customer ORDER BY custId;
* @param
* @author java川
* @date 2021/9/23 17:15
* @return
*/
@Test
public void testSort() {
//得到实体类对象
EntityManager em = JPAUtils.getEntityManager ();
//开启事务
EntityTransaction tx = em.getTransaction ();
tx.begin ();
//jpql语句
String jpqlSql="from Customer ORDER BY custId DESC ";
//query对象执行jpql的对象
Query query = em.createQuery (jpqlSql);
//得到全部数据
List resultList = query.getResultList ();
for (Object o : resultList) {
System.out.println (o+" ");
}
//提交事务
tx.commit ();
em.close ();
}
/*
* @description:
* 统计查询
* sql: select count(*) from cst_customer
* jpql:select count(*) from Customer
* @param
* @author java川
* @date 2021/9/23 17:22
* @return
*/
@Test
public void teststatisticalQuery() {
//得到实体类对象
EntityManager em = JPAUtils.getEntityManager ();
//开启事务
EntityTransaction tx = em.getTransaction ();
tx.begin ();
//jpql语句
String jpqlSql="select count(*) from Customer";
//query对象执行jpql的对象
Query query = em.createQuery (jpqlSql);
//打印结果
Object singleResult = query.getSingleResult ();
System.out.println ("singleResult = " + singleResult);
//提交事务
tx.commit ();
em.close ();
}
/*
* @description:
* 分页查询
* sql: select * from cst_customer limit ?,?
* jpql:
* @param
* @author java川
* @date 2021/9/23 17:29
* @return
*/
@Test
public void testpagingQuery() {
//1得到实体类对象
EntityManager em = JPAUtils.getEntityManager ();
//2开启事务
EntityTransaction tx = em.getTransaction ();
tx.begin ();
//3jpql语句
String jpqlSql="from Customer";
//4query对象执行jpql的对象
Query query = em.createQuery (jpqlSql);
//ii:对占位符参数赋值 ---分页参数
//设置起始索引
query.setFirstResult (0);
//每页查询2条
query.setMaxResults (2);
//iii:发送查询并封装结果
List resultList = query.getResultList ();
//5打印结果
for (Object o : resultList) {
System.out.println (o+" ");
}
//6提交事务
tx.commit ();
em.close ();
}
/*
* @description:
* 条件 分组查询
*
* sql:select * from cst_customer where cust_address like ? group by cust_name
* jpql: from Customer where custAddress like ? group by custName
* @param
* @author java川
* @date 2021/9/23 17:38
* @return
*/
@Test
public void testConditionsTheQuery() {
//1得到实体类对象
EntityManager em = JPAUtils.getEntityManager ();
//2开启事务
EntityTransaction tx = em.getTransaction ();
tx.begin ();
//3jpql语句
String jpqlSql="from Customer where custAddress like ? group by custName";
//4query对象执行jpql的对象
Query query = em.createQuery (jpqlSql);
//ii:对占位符参数赋值 ---分页参数
query.setParameter (1, "%beijing");
//iii:发送查询并封装结果
List resultList = query.getResultList ();
//5打印结果
for (Object o : resultList) {
System.out.println (o+" ");
}
//6提交事务
tx.commit ();
em.close ();
}
}
JPA之原生sql查询
有些时候,JPQL使用不当会导致转化成的sql并不如理想或者特定场合需要sql优化,还是得用到原生SQL查询的。EntityManager
对象的createNativeQuery
方法,可以实现十分复杂的查询,但不能跨数据库。
获得原生SQL查询对象:
Query query = entityManager.createNativeQuery ("select * from cst_customer", Customer.class);
相比jpql只是将entityManager.createQuery(String jpql)
改为entityManager.createNativeQuery(String sql);
jpa-原生SQL增删改查
package com.zhangchuan.test;
import com.zhangchuan.jpa.entity.Customer;
import com.zhangchuan.jpa.utils.JPAUtils;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import java.util.List;
/**
* @Description 原生的sql查询,jpql有时候使用不当还是要用原生sql
* jpql的好处就是自动映射查询结果到对象中,原生sql查询需要手动映射结果到对象中。
* @Author java川
* @Date 2021-09-24-9:50
*/
public class RawSqlTest {
/*
* @description:
* 排序查询 sql:select * from cst_customer order by cust_id desc
* @param
* @author java川
* @date 2021/9/24 10:03
* @return
*/
@Test
public void testOrder() {
// 1.获取entityManager对象 && 开启事务
EntityManager entityManager = JPAUtils.getEntityManager ();
EntityTransaction transaction = entityManager.getTransaction ();
transaction.begin ();
// 采用链式调用,默认情况(升序)
List<Customer> list1 = entityManager.createNativeQuery ("select * from cst_customer order by cust_id", Customer.class).getResultList ();
// 采用链式调用,升序情况
List<Customer> list2 = entityManager.createNativeQuery ("select * from cst_customer order by cust_id asc ", Customer.class).getResultList ();
// 采用链式调用,降序情况
List<Customer> list3 = entityManager.createNativeQuery ("select * from cst_customer order by cust_id desc", Customer.class).getResultList ();
for (Customer customer : list1) {
System.out.println (customer);
}
for (Customer customer : list2) {
System.out.println (customer);
}
for (Customer customer : list3) {
System.out.println (customer);
}
// 4.提交事务 && 释放资源
transaction.commit ();
entityManager.close ();
}
/**
* 条件查询
* sql:SELECT * FROM cst_customer where c_sex = ?1 and c_name like ?2
* sql:SELECT * FROM cst_customer where c_sex = :aaa and c_name like :bbb
*/
@Test
public void testWhere() {
// 1.获取entityManager对象 && 开启事务
EntityManager entityManager = JPAUtils.getEntityManager ();
EntityTransaction transaction = entityManager.getTransaction ();
transaction.begin ();
// 条件查询:按参数位置绑定
Query query1 = entityManager.createNativeQuery ("SELECT * FROM cst_customer where cust_address like ? group by cust_name", Customer.class);
query1.setParameter (1, "beijing%");
List<Customer> list1 = query1.getResultList ();
for (Customer customer : list1) {
System.out.println (customer);
}
// 4.提交事务 && 释放资源
transaction.commit ();
entityManager.close ();
}
/**
* 分页查询 sql:select * from cst_customer limit 2,5
* sql:select * from cst_customer limit 3 offset 2
*/
@Test
public void testLimit() {
// 1.获取entityManager对象 && 开启事务
EntityManager entityManager = JPAUtils.getEntityManager ();
EntityTransaction transaction = entityManager.getTransaction ();
transaction.begin ();
// 分页查询
Query query = entityManager.createNativeQuery ("select * from cst_customer limit 3 offset 2", Customer.class);
// 起始索引、每页查询的条数
// query.setFirstResult(2).setMaxResults(5);
List<Customer> list1 = query.getResultList ();
for (Customer customer : list1) {
System.out.println (customer);
}
// 4.提交事务 && 释放资源
transaction.commit ();
entityManager.close ();
}
}