JDBC 怎么保存数据的 ?
实体类
public class User{
private Integer userId;
private String username;
}
数据库表
create table t_user(
id int auto_increament,
username varchar,
address varchar
)
将对象存到 数据库表中
- 注册驱动, 获取连接
- 创建PreparedStatment 对象
- 对SQL语句进行占位符的赋值
- 执行SQL
JDBC中出现的问题以及如何解决
解决操作繁琐 : 封装JDBC到工具类
解决SQL占位符问题 : 通过 obj.save(user);
对象.方法名(传递实体类对象);
String sql = "insert into __ (字段名1, ...)";
SQL语句 可以拆分成 需要添加的内容 和
固定的内容
引入ORM思想
操作实体类就相当于操作数据库表
怎么做?
将实体类和数据库表字段建立关系
实体类的属性 和 数据库表字段建立关系
ORM思想 : 操作实体类就相当于操作数据库表
两个映射关系
- 实体类和表的关系
- 实体类的属性和表中字段的关系
实现ORM思想的框架
Hibernate 开源 ORM 框架
轻量级封装 JDBC
POJO Java实体类对象与数据库表建立映射关系,
全自动的ORM框架
Hibernate可以自动生成SQL语句
首先是一个ORM框架 对JDBC进行封装
JPA规范
实现ORM思想的框架太多 sun公司定义ORM思想规范 就是JPA规范 一些接口和抽象类
说一下规范
数据库的规范 JDBC规范
Java代码全都使用的是JDBC的规范来操作数据库
当修改数据库的时候只需要配置
JPA
Java持久化 API
jdk5.0 后通过注解描述映射关系
JPA的基本操作
客户表: sql表
/*创建客户表*/
CREATE TABLE cst_customer (
cust_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
cust_name varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
cust_source varchar(32) DEFAULT NULL COMMENT '客户信息来源',
cust_industry varchar(32) DEFAULT NULL COMMENT '客户所属行业',
cust_level varchar(32) DEFAULT NULL COMMENT '客户级别',
cust_address varchar(128) DEFAULT NULL COMMENT '客户联系地址',
cust_phone varchar(64) DEFAULT NULL COMMENT '客户联系电话',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
搭建环境的过程
- 创建Maven工程 导入坐标
- 配置JPA的核心配置文件
- 创建客户的实体类
- 配置客户的实体类和数据库表, 实体类中的属性和数据库表中字段的映射
- 将客户保存到数据库中
配置核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
<!-- jpa的实现方式-->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- 数据库信息-->
<properties>
<!-- 数据库驱动 -->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<!-- 数据库地址 -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa" />
<!-- 数据库用户名 -->
<property name="javax.persistence.jdbc.user" value="root" />
<!-- 数据库密码 -->
<property name="javax.persistence.jdbc.password" value="root" />
<!--jpa提供者的可选配置:我们的JPA规范的提供者为hibernate,所以jpa的核心配置中兼容hibernate的配置-->
<!-- 显示SQL :
自动创建数据库表 : hibernate.hbm2ddl.auto
create : 程序运行时创建数据库表 (有表的话会删除表再创建)
update : 程序运行时创建表(有表的话,不会创建表)
none : 不会创建表
value 的值 为 update create 没有表会创建表
-->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
<!-- 配置jpa的实现方式的配置信息-->
</persistence-unit>
</persistence>
实体类
package cn.ljx.domain;
/**
* @Author: Luokexi
* @Date: 2019/1/10 22:04
* 明确需求,整理思路,步步实现,规范编写,测试功能,总结经验.
*/
public class Customer {
/**
* 客户的主键
* 客户名称
* 客户来源
* 客户级别
* 客户所属行业
* 客户的联系方式
* 客户地址
*/
private Long custId;
private String custName;
private String custSource;
private String custIndustry;
private String custLevel;
private String custAddress;
private String custPhone;
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 getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
}
主键生成策略的说明
主键生成策略的形式 根据底层MySQL支持的是自增形式
通过数据库表的形式 完成自增
auto 程序自动选择
Jpa步骤详解 程序执行流程不够明晰
- 加载配置文件创建实体管理器工厂
Persisitence.createEntityManagerFactory(配置文件中配置的持久化单元名)
- 根据实体管理器工厂 创建实体管理器对象
EntityManagerFactory: 获取EntityManager对象
因为内部维护了很多内容 比如说 数据库信息, 缓存信息, 实体管理器对象, 创建一个工厂比较耗资源
* EntityManagerFactory的创建过程比较浪费资源
特点:线程安全的对象
多个线程访问同一个EntityManagerFactory不会有线程安全问题
* 如何解决EntityManagerFactory的创建过程浪费资源(耗时)的问题?
思路:创建一个公共的EntityManagerFactory的对象
* 静态代码块的形式创建EntityManagerFactory
- 创建事务对象,开启事务
EntityManager对象:实体类管理器
beginTransaction : 创建事务对象
presist : 保存
merge : 更新
remove : 删除
find/getRefrence : 根据id查询
Transaction 对象 : 事务
begin:开启事务
commit:提交事务
rollback:回滚
- 增删改查操作
- 提交事务
- 释放资源
延迟加载和立即加载
find() 立即加载 和 getReference() 什么时候用什么时候加载 懒加载 动态代理对象
不会浪费资源
Jpa的基本API操作
保存操作
entityManager.persist(实体类);
查询操作
entityManager.find(); 立即加载
entityManager.getReference; 延迟加载
删除操作 (先查再删除)
entityManager.remove();
更新操作(查出结果更新数据)
entityManager.merge();
jpql查询
Jpa提供的查询语句 查询实体类和实体类中的属性
应用场景 复杂查询
- 查询全部
from 实体类名
- 分页查询
开始的索引
query.setFirstResult(0);
每页显示的条目
query.setMaxResults(2);
-
统计查询
聚合函数 SQL count() -
条件查询
from Customer where custName like ?
第一个占位符索引位置 , 第二个占位符内容
// select 字段 from 表 where 字段 like
String jspl = "from Customer where cust_name like ?";
Query query = entityManager.createQuery(jspl);
// arg0: 占位符的索引位置(从1开始) arg1: 占位符的内容
query.setParameter(1,"王%");
- 排序
// 根据主键降序
String jpql = "from Customer order by cust_id desc";
实例代码
package cn.ljx.test;
import cn.ljx.domain.Customer;
import cn.ljx.utils.JpaUtlis;
import org.junit.Test;
import javax.persistence.*;
import java.util.List;
/**
* @Author: Luokexi
* @Date: 2019/1/10 22:33
* 明确需求,整理思路,步步实现,规范编写,测试功能,总结经验.
*/
public class JpaTest {
/**
* 添加(保存)
*/
@Test
public void testSave(){
// 1. 加载配置文件 创建工厂(实体管理工厂) 对象
// EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
// 2. 通过实体类管理器工厂获取实体管理器
// EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityManager entityManager = JpaUtlis.getEntityManager();
// 3.0 在进行增删改操作之前 要获取事务对象
EntityTransaction transaction = entityManager.getTransaction();
// 3.1 开启事务
transaction.begin();
// 3.2 封装数据
Customer customer = new Customer();
customer.setCustAddress("杭州");
customer.setCustIndustry("Android 开发");
customer.setCustName("王二珂");
// 4. 完成增删改操作
entityManager.persist(customer);
// 5. 事务提交 事务的回滚
transaction.commit();
// 6. 释放资源 后开的资源先放
entityManager.close();
// 此时工厂是公共的 使用后不能关闭 否则其他对象就获取不到该工厂
// entityManagerFactory.close();
}
/**
* 查询
*/
@Test
public void testFind(){
// 1. 通过JpaUtils获取
EntityManager entityManager = JpaUtlis.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
// 2. 开启事务
transaction.begin();
// 3. 查询结果封装的对象.class, 主键值
Customer customer = entityManager.find(Customer.class, 3l);
System.out.println("查询的结果: ");
System.out.println(customer);
transaction.commit();
entityManager.close();
}
/**
* 延迟加载 用的时候加载
*/
@Test
public void testReference(){
// 1. 通过JpaUtils获取
EntityManager entityManager = JpaUtlis.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
// 2. 开启事务
transaction.begin();
// 3. 查询结果封装的对象.class, 主键值
Customer customer = entityManager.getReference(Customer.class, 2l);
System.out.println("查询的结果: ");
System.out.println(customer);
transaction.commit();
entityManager.close();
}
/**
* 移除
*/
@Test
public void testRemove(){
// 1. 通过JpaUtils获取
EntityManager entityManager = JpaUtlis.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
// 2. 开启事务
transaction.begin();
// 3. 查询结果封装的对象.class, 主键值
Customer customer = entityManager.find(Customer.class, 2l);
// 4. 调用remove方法 直接删除
entityManager.remove(customer);
System.out.println("查询结果: " + customer);
transaction.commit();
entityManager.close();
}
/**
* 更新
*/
@Test
public void testUpdate(){
// 1. 通过JpaUtils获取
EntityManager entityManager = JpaUtlis.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
// 2. 开启事务
transaction.begin();
// 3. 查询结果封装的对象.class, 主键值
Customer customer = entityManager.find(Customer.class, 1l);
// 4. 更新数据
customer.setCustName("光光头头哥哥");
entityManager.merge(customer);
// 5. 提交事务
transaction.commit();
// 6. 关闭资源
entityManager.close();
}
/**
* 查询全部
* jqpl:from cn.itcast.domain.Customer
* sql:SELECT * FROM cst_customer
*/
@Test
public void testFindAll(){
//
EntityManager entityManager = JpaUtlis.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
// 编写 jpql 查询全部
//3.查询全部
String jpql = "from cn.itcast.domain.Customer ";
Query query = entityManager.createQuery(jpql);//创建Query查询对象,query对象才是执行jqpl的对象
//发送查询,并封装结果集
List list = query.getResultList();
for (Object obj : list) {
System.out.print(obj);
}
//4.提交事务
transaction.commit();
//5.释放资源
entityManager.close();
}
/**
* 查询总数
*/
@Test
public void testCount(){
//
EntityManager entityManager = JpaUtlis.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
// 编写 jpql
String jpql = "select count (cust_id) from Customer";
Query query = entityManager.createQuery(jpql);
Object singleResult = query.getSingleResult();
System.out.println("查询的总数: "+ singleResult);
transaction.commit();
entityManager.close();
}
/**
* 分页查询
*/
@Test
public void testPage(){
EntityManager entityManager = JpaUtlis.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
String jspl = "from Customer";
Query query = entityManager.createQuery(jspl);
// 开始的索引
query.setFirstResult(0);
// 每页显示的条目
query.setMaxResults(2);
List resultList = query.getResultList();
System.out.println("分页查询");
for (Object o : resultList) {
System.out.println(o);
}
}
/**
* 条件查询
*/
@Test
public void testCondition(){
EntityManager entityManager = JpaUtlis.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
// select 字段 from 表 where 字段 like
String jspl = "from Customer where cust_name like ?";
Query query = entityManager.createQuery(jspl);
// arg0: 占位符的索引位置(从1开始) arg1: 占位符的内容
query.setParameter(1,"王%");
List resultList = query.getResultList();
System.out.println("条件查询的结果");
for (Object o : resultList) {
System.out.println(o);
}
transaction.commit();
entityManager.close();
}
/**
* 排序
*/
@Test
public void testOrder(){
EntityManager entityManager = JpaUtlis.getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
// 根据主键降序
String jpql = "from Customer order by cust_id desc";
// 通过实体管理器对象 创建查询对象 传入 jqpl
Query query = entityManager.createQuery(jpql);
List resultList = query.getResultList();
System.out.println("主键降序排序的结果: ");
for (Object o : resultList) {
System.out.println(o);
}
transaction.commit();
entityManager.close();
}
}