摘要
工作中用到了mybatis,之后又用到了类似的持久层jpa,当时是真的给我惊艳了,觉的这玩意可真是牛逼。
甚至不用手动来操作数据库了,直接面向对象,方便了许多。
正文
源码
一、ORM 1.1 回顾JDBC 在以往的与数据库的交互中,我们一般是如下图操作的
展开
问题
操作繁琐 占位符赋值麻烦 那么如何解决呢?
建立实体类和表的关系 建立实体类中属性和表中字段的关系 这样,我们就可以直接通过调用方法,来实现增删改查。比如增加
1
obj . save ( user ); // 相当于执行 insert into user values ( user . getId (), user . getName );
1.2 ORM思想 思想:操作实体类就相当于操作数据库表
建立两个映射关系
实体类和表的映射关系 实体类中属性和表中字段的映射关系 好处:不用关注SQL语句
目前市面上,有好多实现ORM思想的框架
mybatis hibernate jpa 1.3 Hibernate框架 Hibernate是一个开放源代码的对象关系映射框架。
它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架。
Hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
二、JPA概述 2.1 JPA规范 市面上有很多ORM框架,Sun公司为了实现统一,自己定义了一套ORM规范,就叫JPA(Java Persistence API)。内部是由接口和抽象类组成。
JDBC规范,如果要操纵数据库,需要用到驱动,具体实现的逻辑由驱动提供。JDBC规范的好处是,如果我们更换了数据库,只需更换数据库驱动即可,Java代码仍然可以复用。
JPA规范,实现方式有Hibernate、topLink等。JPA规范的好处是,更换实现方式,代码仍然可以复用,只需要修改实现方式即可。
2.2 JPA优势 优势
任何符合JPA标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的应用经过少量的修改就能在不同的JPA框架下运行。 JPA框架支持大数据集、事务、并发等容器级事务。 JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句。JPA定义了JPQL,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、Join、Group By、Having等通常只有SQL才能够提供的高级查询特性,甚至还能够支持子查询。 JPA中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系。 2.3 JPA与Hibernate的关系 JPA规范本质上就是一种ORM规范,注意不是ORM框架,因为JPA并未提供ORM实现,它只是制定了一些规范,提供了一些编程的API接口,但是具体的实现则由服务厂商来提供实现。
展开
三、JPA入门案例 3.1 需求 保存客户到数据库的客户表中
1
2
3
4
5
6
7
8
9
10
11
/*创建客户表*/
CREATE TABLE 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 ;
3.2 环境 步骤
maven导入坐标 添加log4j配置文件 配置jpa的核心配置文件位置:配置到类路径下的一个叫做META-INF的文件夹下 命名:persistence.xml 约束配置:idea右键new->EditFileTemplate->Other->JPA->Deployment descriptors 编写客户实体类 配置实体类和表、类中属性和表中字段的映射关系 保存客户到数据库中 maven中导入坐标 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns= "http://maven.apache.org/POM/4.0.0"
xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
<modelVersion> 4.0.0</modelVersion>
<groupId> top.meethigher</groupId>
<artifactId> SpringDataJPA-notes</artifactId>
<version> 1.0</version>
<properties>
<project.build.sourceEncoding> UTF-8</project.build.sourceEncoding>
<project.hibernate.version> 5.4.30.Final</project.hibernate.version>
</properties>
<dependencies>
<dependency>
<groupId> junit</groupId>
<artifactId> junit</artifactId>
<version> 4.13</version>
<scope> test</scope>
</dependency>
<!--hibernate对jpa的支持包-->
<dependency>
<groupId> org.hibernate</groupId>
<artifactId> hibernate-entitymanager</artifactId>
<version> ${project.hibernate.version}</version>
</dependency>
<!--c3p0-->
<dependency>
<groupId> org.hibernate</groupId>
<artifactId> hibernate-c3p0</artifactId>
<version> ${project.hibernate.version}</version>
</dependency>
<!--log日志-->
<dependency>
<groupId> log4j</groupId>
<artifactId> log4j</artifactId>
<version> 1.2.17</version>
</dependency>
<dependency>
<groupId> mysql</groupId>
<artifactId> mysql-connector-java</artifactId>
<version> 8.0.12</version>
</dependency>
</dependencies>
</project>
添加log4j配置文件 在resources目录下添加即可
可以参照mybatis 中的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#############
# 输出到控制台
#############
# log4j.rootLogger日志输出类别和级别:只输出不低于该级别的日志信息DEBUG < INFO < WARN < ERROR < FATAL
# WARN:日志级别 CONSOLE:输出位置自己定义的一个名字 logfile:输出位置自己定义的一个名字
log4j.rootLogger = debug,CONSOLE,logfile
# 配置CONSOLE输出到控制台
log4j.appender.CONSOLE = org.apache.log4j.ConsoleAppender
# 配置CONSOLE设置为自定义布局模式
log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout
# 配置CONSOLE日志的输出格式 [frame] 2019-08-22 22:52:12,000 %r耗费毫秒数 %p日志的优先级 %t线程名 %C所属类名通常为全类名 %L代码中的行号 %x线程相关联的NDC %m日志 %n换行
log4j.appender.CONSOLE.layout.ConversionPattern = [frame] %d{yyyy-MM-dd HH:mm:ss,SSS} - %-4r %-5p [%t] %C:%L %x - %m%n
################
# 输出到日志文件中
################
# 配置logfile输出到文件中 文件大小到达指定尺寸的时候产生新的日志文件
log4j.appender.logfile = org.apache.log4j.RollingFileAppender
# 保存编码格式
log4j.appender.logfile.Encoding = UTF-8
# 输出文件位置此为项目根目录下的logs文件夹中
log4j.appender.logfile.File = logs/root.log
# 后缀可以是KB,MB,GB达到该大小后创建新的日志文件
log4j.appender.logfile.MaxFileSize = 10MB
# 设置滚定文件的最大值3 指可以产生root.log.1、root.log.2、root.log.3和root.log四个日志文件
log4j.appender.logfile.MaxBackupIndex = 3
# 配置logfile为自定义布局模式
log4j.appender.logfile.layout = org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %F %p %m%n
##########################
# 对不同的类输出不同的日志文件
##########################
# club.bagedate包下的日志单独输出
log4j.logger.club.bagedate = DEBUG,bagedate
# 设置为false该日志信息就不会加入到rootLogger中了
log4j.additivity.club.bagedate = false
# 下面就和上面配置一样了
log4j.appender.bagedate = org.apache.log4j.RollingFileAppender
log4j.appender.bagedate.Encoding = UTF-8
log4j.appender.bagedate.File = logs/bagedate.log
log4j.appender.bagedate.MaxFileSize = 10MB
log4j.appender.bagedate.MaxBackupIndex = 3
log4j.appender.bagedate.layout = org.apache.log4j.PatternLayout
log4j.appender.bagedate.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %F %p %m%n
☆配置jpa核心文件 在Maven下的resources文件夹下创建META-INF文件夹。
在META-INF文件夹下添加persistence.xml。
利用idea中的jpa模板来复制xml约束,步骤如图。
展开
配置持久化单元节点persistence-unit
name:持久化单元名称 transaction-type:事务管理方式JTA:分布式事务管理。适用于不同的表存在于不同的数据库中 RESOURCE_LOCAL:本地事务管理。所有的表都存在于一个数据库中 配置jpa实现方式
provider标签:org.hibernate.jpa.HibernatePersistenceProvider 配置数据库信息property
javax.persistence.jdbc.user:用户名
javax.persistence.jdbc.password:密码
javax.persistence.jdbc.driver:驱动
javax.persistence.jdbc.url:数据库地址
配置jpa实现方(hibernate)信息property
hibernate.show_sql:显示sql,值为true或false,默认false hibernate.hbm2ddl.auto:自动创建数据库,值有create、update、none,默认updatecreate:程序运行时创建表,如果有表,那就先删除再创建 update:程序运行时创建表,如果有表,不会创建表 none:不会创建表 persistence.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns= "http://java.sun.com/xml/ns/persistence" version= "1.0" >
<!--配置persistence-unit节点-->
<persistence-unit name= "myJpa" transaction-type= "RESOURCE_LOCAL" >
<!--jpa的实现方式-->
<provider> org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!--可选配置:-->
<properties>
<property name= "javax.persistence.jdbc.user" value= "root" />
<property name= "javax.persistence.jdbc.password" value= "root" />
<property name= "javax.persistence.jdbc.driver" value= "com.mysql.cj.jdbc.Driver" />
<property name= "javax.persistence.jdbc.url " value= "jdbc:mysql://localhost:3306/springdatajpa?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai" />
<property name= "hibernate.show_sql" value= "true" />
<property name= "hibernate.hbm2ddl.auto" value= "create" />
</properties>
</persistence-unit>
</persistence>
编写客户实体类 根据数据库来创建实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package top.meethigher.demo01.domain ;
/**
* Customer
*
* @author kit chen
* @github https://github.com/meethigher
* @blog https://meethigher.top
* @time 2021/4/10
*/
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 ;
}
@Override
public String toString () {
return "Customer{" +
"custId=" + custId +
", custName='" + custName + '\'' +
", custSource='" + custSource + '\'' +
", custIndustry='" + custIndustry + '\'' +
", custLevel='" + custLevel + '\'' +
", custAddress='" + custAddress + '\'' +
", custPhone='" + custPhone + '\'' +
'}' ;
}
}
☆配置映射关系 使用注解配置
实体类和表的映射关系 类中属性和表中字段的映射关系 注解
@Entity:声明该类 是一个实体类 @Table:配置实体类和表的映射关系 @Id:表示当前属性或者变量 是主键 @GeneratedValuestrategy:配置主键的生成策略GenerationType.IDENTITY,表示自增,前提是底层数据库必须支持自动增长,如mysql,postgresql GenerationType.SEQUENCE,表示序列,前提是底层数据库必须支持序列,如oracle GenerationType.TABLE,jpa提供的一种机制,通过在数据库中多建立一张数据库表的形式,用来存储下一个的值,帮助我们完成自增(就跟我当初做的住房公积金系统的需求一样) GenerationType.AUTO,由程序自动选择策略 @Column:配置实体类属性和表中字段的映射关系 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
@Entity
@Table ( name = "customer" )
public class Customer {
@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_industry" )
private String custIndustry ;
@Column ( name = "cust_level" )
private String custLevel ;
@Column ( name = "cust_address" )
private String custAddress ;
@Column ( name = "cust_phone" )
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 ;
}
@Override
public String toString () {
return "Customer{" +
"custId=" + custId +
", custName='" + custName + '\'' +
", custSource='" + custSource + '\'' +
", custIndustry='" + custIndustry + '\'' +
", custLevel='" + custLevel + '\'' +
", custAddress='" + custAddress + '\'' +
", custPhone='" + custPhone + '\'' +
'}' ;
}
}
测试保存客户到数据库中 如果是update或者create时,添加实体类字段,会添加相应的字段。区别在于一个是直接在原有数据基础上添加字段,另一个是删除表再添加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class JPATest01 {
@Test
public void testSave () {
/*1. 加载配置文件创建工厂(实体管理类工厂)对象*/
EntityManagerFactory factory = Persistence . createEntityManagerFactory ( "myJpa" );
/*2. 通过实体管理类工厂获取实体管理器*/
EntityManager em = factory . createEntityManager ();
/*3. 获取事务对象,开启事务*/
EntityTransaction ts = em . getTransaction ();
ts . begin ();
/*4. 完成增删改查操作*/
Customer customer = new Customer ();
customer . setCustName ( "美杜莎" );
customer . setCustIndustry ( "蛇人族" );
customer . setCustAddress ( "斗破苍穹" );
customer . setCustLevel ( "斗皇强者" );
customer . setCustPhone ( "保密" );
customer . setCustSource ( "保密" );
em . persist ( customer );
/*5. 提交事务(回滚事务)*/
ts . commit ();
/*6. 释放资源*/
em . close ();
factory . close ();
}
}
四、JPA基本操作 4.1 步骤 jpa操作步骤
加载配置文件创建实体管理工厂Persistence:静态方法,createEntityManagerFactory根据持久化单元名称创建实体管理工厂 根据实体管理工厂,创建实体管理器EntityManagerFactory:获取EntityManagerFactory对象,createEntityManager创建实体管理器内部维护了数据库信息 内部维护了缓存信息 维护了所有的实体管理对象 在创建EntityManagerFactory的过程中,会根据配置创建数据库表 EntityManagerFactory的创建过程比较浪费资源、耗时 特点:EntityManagerFactory是一个线程安全的对象,也就是多个线程访问同一个EntityManagerFactory不会有线程安全问题 如何解决EntityManagerFactory的创建过程浪费资源、耗时的问题?静态代码块的形式创建一个公共的EntityManagerFactory的对象 创建事务对象,开启事务EntityManager对象:实体类管理器beginTransaction:创建事务对象 presist:保存 merge:更新 remove:删除 find/getReference:根据id查询class参数:查询的数据结果需要包装成的实体类类型的的字节码 id参数:要查询的主键的取值 getReference获取到的是一个动态代理 对象,可以通过断点看到。而且,该方法采用的是懒加载 的方式。 find获取到的就是对象本身,是立即加载。 Transaction对象:事务begin:开启事务 commit:提交事务 rollback:回滚 增删改查操作 提交事务 释放资源 4.2 实现 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public class JPATest02 {
/**
* 保存
*/
@Test
public void testSave () {
EntityManager em = JpaUtils . getEntityManager ();
EntityTransaction ts = em . getTransaction ();
ts . begin ();
Customer customer = new Customer ();
customer . setCustName ( "美杜莎" );
customer . setCustIndustry ( "蛇人族" );
customer . setCustAddress ( "斗破苍穹" );
customer . setCustLevel ( "斗皇强者" );
customer . setCustPhone ( "保密" );
customer . setCustSource ( "保密" );
em . persist ( customer );
ts . commit ();
em . close ();
}
/**
* 查询
*/
@Test
public void testFind () {
EntityManager em = JpaUtils . getEntityManager ();
EntityTransaction ts = em . getTransaction ();
ts . begin ();
/**
* find:根据id查询,立即加载
* getReference:根据id查询,通过代理实现懒加载
*/
// Customer customer = em.find(Customer.class, 1L);//注意此处是1L,否则会报Long转Integer错误
Customer customer = em . getReference ( Customer . class , 1L );
ts . commit ();
em . close ();
}
/**
* 删除
* 先查再删
*/
@Test
public void testDelete () {
EntityManager em = JpaUtils . getEntityManager ();
EntityTransaction ts = em . getTransaction ();
ts . begin ();
/**
* 删除
* 1. 先查
* 2. 再删
*/
Customer reference = em . getReference ( Customer . class , 1L );
em . remove ( reference );
ts . commit ();
em . close ();
}
/**
* 修改
* 先查再改
*/
@Test
public void testUpdate (){
EntityManager em = JpaUtils . getEntityManager ();
EntityTransaction ts = em . getTransaction ();
ts . begin ();
/**
* 删除
* 1. 先查
* 2. 再删
*/
Customer reference = em . getReference ( Customer . class , 3L );
reference . setCustName ( "胡列娜" );
em . merge ( reference );
ts . commit ();
em . close ();
}
}
五、JPQL复杂查询 5.1 概念 JPQL全称Java Persistence Query Language,Java持久化查询语言,以面向对象的表达式 ,将SQL语法和简单语义绑定在一起,可以被编译成所有主流数据库服务器上的SQL。
SQL:查询的是表和表中的字段
JPQL:查询的是实体类和表中的属性
5.2 操作 首先准备单元测试的环境
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class JPQLTest {
private static EntityManager em ;
private static EntityTransaction ts ;
@BeforeClass
public static void beforeClass () throws Exception {
em = JpaUtils . getEntityManager ();
ts = em . getTransaction ();
ts . begin ();
System . out . println ( "获取对象并开启事务" );
}
@AfterClass
public static void afterClass () throws Exception {
ts . commit ();
em . close ();
System . out . println ( "提交事务并释放对象" );
}
}
查询全部 SQL:select * from customer
JPQL:from top.meethigher.Customer(也可以省略全类名,只用类名即可)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 查询全部
*/
@Test
public void testFindAll () {
String jpql = "from Customer" ;
//创建Query对象,Query才是执行JPQL的对象
Query query = em . createQuery ( jpql );
//发送查询,并封装结果集
List resultList = query . getResultList ();
//遍历
for ( Object o :
resultList ) {
System . out . println ( o );
}
}
排序查询 SQL:select * from customer order by cust_id desc
JPQL:from top.meethigher.Customer order by custId desc(也可以省略全类名,只用类名即可)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 排序查询
*/
@Test
public void testFindOrById () {
String jpql = "from Customer order by custId desc " ;
//创建Query对象,Query才是执行JPQL的对象
Query query = em . createQuery ( jpql );
//发送查询,并封装结果集
List resultList = query . getResultList ();
//遍历
for ( Object o :
resultList ) {
System . out . println ( o );
}
}
统计查询 SQL:select count(cust_id) from customer
JPQL:select count(custId) from top.meethigher.Customer (也可以省略全类名,只用类名即可)
1
2
3
4
5
6
7
8
9
10
/**
* 统计查询
*/
@Test
public void testFindCount () {
String jpql = "select count(custId) from Customer" ;
Query query = em . createQuery ( jpql );
Object singleResult = query . getSingleResult ();
System . out . println ( singleResult );
}
分页查询 SQL
标准写法:select * from customer limit ?,? 省略写法:如果是从0开始,那么可省略。select * from customer limit ? JPQL:from top.meethigher.Customer (也可以省略全类名,只用类名即可)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 分页查询
*/
@Test
public void testFindByPage () {
String jpql = "from Customer" ;
Query query = em . createQuery ( jpql );
//分页查询
//起始索引
query . setFirstResult ( 1 );
//每页查询的条数
query . setMaxResults ( 2 );
List resultList = query . getResultList ();
for ( Object o :
resultList ) {
System . out . println ( o );
}
}
条件查询 查询名称含有xx关键字的客户
SQL:select * from customer where cust_name like ?
JPQL:from top.meethigher.Customer where custName like ?1(也可以省略全类名,只用类名即可)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 条件查询
*/
@Test
public void testFindByCondition () {
String jpql = "from Customer where custName like ?1" ;
Query query = em . createQuery ( jpql );
//条件查询
/**
* 占位符参数
* 第一个参数:占位符索引位置,从1开始
* 第二个参数:取值
*/
query . setParameter ( 1 , "%美%" );
List resultList = query . getResultList ();
for ( Object o :
resultList ) {
System . out . println ( o );
}
}