Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JavaEE架构中取代CMP,完成数据持久化的重任。
/*创建客户表*/
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;
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.hibernate.version>5.0.7.Finalproject.hibernate.version>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>${project.hibernate.version}version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-c3p0artifactId>
<version>${project.hibernate.version}version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.6version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.16version>
dependency>
dependencies>
//标志实体类
@Entity
//映射表
@Table(name = "cst_customer")
//添加get()set方法
@Data
public class Customer implements Serializable {
@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 custIevel;
@Column(name = "cust_address")
private String custAddress;
@Column(name = "cust_phone")
private String custPhone;
}
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<provider>org.hibernate.jpa.HibernatePersistenceProviderprovider>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://192.168.93.222:3306/day19?useUnicode=true&characterEncoding=UTF-8"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="hibernate.show_sql" value="true"/>
properties>
persistence-unit>
persistence>
核心步骤
* 步骤:
* 1、加载配置文件创建实体类管理器工厂
* 2、通过工厂 创建实体类管理器
* 3、获取事务对象
* 4、开启事务
* 5、CRUD:保存客户实体
* 6、提交事务
* 7、释放资源
测试代码
@Test
public void show(){
Customer customer = new Customer();
customer.setCustName("行健乖乖把");
customer.setCustIevel("永恒砖石");
//步骤:
//1、加载配置文件创建实体类管理器工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
//2、通过工厂 创建实体类管理器
EntityManager entityManager = factory.createEntityManager();
//3、获取事务对象
EntityTransaction tx = entityManager.getTransaction();
//4、开启事务
tx.begin();
//5、CRUD:保存客户实体
entityManager.persist(customer);
//6、提交事务
tx.commit();
//7、释放资源
entityManager.close();
factory.close();
}
创建工程,添加依赖
创建实体类和创建数据库
进行JPA的映射
配置JPA的核心文件
测试保存一个用户
1、Persistence 重要程度:一般
作用:用于加载配置文件创建实体类管理器工厂
主要方法:
createEntityManagerFactory("持久化单元名称")
2、EntityManagerFactory 重要程度:比较重要
作用:用于创建实体类管理器
常用方法:
createEntityManager()
close()
细节:
1、这个类是个重量级的类:维护了全字段的CRUD的sql语句,二级缓存
2、这个类是线程安全的类,多线程环境下不会出现线程安全并发问题
使用:
一个web项目应该只有一个这个对象
3、EntityManager 重要程度:非常重要
作用:与数据库的交互都是他完成,事务对象也是他获取的
常用的方法:
getTransaction()
persist()
close
find
getReference
....
细节:
1、由于工厂已经维护了较多的信息,所以这个类维护的信息就少了,所以他是一个轻量级对象
2、他是线程不安全的
使用:
一个线程只有一个这个对象,一次请求
4、EntityTransaction 重要程度:会用就行
作用:控制事务
常用方法:
begin
commit
rollback
public class JpaUtil {
private static EntityManagerFactory myJpa;
/*
* 静态的加载
* */
static {
myJpa = Persistence.createEntityManagerFactory("myJpa");
}
/*
* 实体类管理器
* */
public static EntityManager getEntityManager(){
return myJpa.createEntityManager();
}
/*
* 关闭资源
* */
public static void close(EntityManager entityManager){
if (entityManager!=null){
entityManager.close();
}
}
}
/*
* 添加数据包
* */
@Test
public void show(){
Customer customer = new Customer();
customer.setCustName("行健乖乖把");
customer.setCustIevel("VIP");
EntityManager entityManager = JpaUtil.getEntityManager();
// //3、获取事务对象
EntityTransaction tx = entityManager.getTransaction();
//4、开启事务
tx.begin();
//5、CRUD:保存客户实体
entityManager.persist(customer);
//6、提交事务
tx.commit();
//7、释放资源
JpaUtil.close(entityManager);
}
/*
* 删除数据
* */
@Test
public void delete(){
//获取实体类管理器
EntityManager entityManager = JpaUtil.getEntityManager();
// 获取事务对象
EntityTransaction tx = entityManager.getTransaction();
//开启事务
tx.begin();
Customer customer1 = entityManager.find(Customer.class, 1L);
entityManager.remove(customer1);
// 提交事务
tx.commit();
//
JpaUtil.close(entityManager);
}
/*
* 更新数据
* */
@Test
public void update(){
// 获取实体类的管理器
EntityManager entityManager = JpaUtil.getEntityManager();
// 获取事务对象
EntityTransaction tx= entityManager.getTransaction();
// 开启事务
tx.begin();
//先查询在更新
Customer customer = entityManager.find(Customer.class, 2L);
customer.setCustName("来了老弟");
entityManager.persist(customer);
// 提交事务
tx.commit();
JpaUtil.close(entityManager);
}
/*
* 查询全部数据
* */
@Test
public void findList(){
EntityManager entityManager = JpaUtil.getEntityManager();
Query query = entityManager.createQuery("from Customer");
List<Customer> resultList = query.getResultList();
resultList.forEach(o-> System.out.println("o = " + o));
}
/*
* 根据id查询数据
* */
@Test
public void findById(){
// 获取实体类的管理器
EntityManager entityManager = JpaUtil.getEntityManager();
//根据id查询信息
Customer customer = entityManager.find(Customer.class, 2L);
System.out.println("customer = " + customer);
}
@Test
public void show(){
EntityManager entityManager = JpaUtil.getEntityManager();
String sql="from Customer";
Query query = entityManager.createQuery(sql);
List resultList = query.getResultList();
resultList.forEach(o -> System.out.println("o = " + o));
}
JPA分页分析:
mysql: limit ? 查询前面n条
limit ? ,?
第一个参数:开始索引=(当前页-1)* 页大小
第二个参数:页大小
/*
* 分页
* */
@Test
public void show1(){
EntityManager entityManager = JpaUtil.getEntityManager();
Query query = entityManager.createQuery("from Customer ");
// 设置分页条件 :页大小
query.setFirstResult(1); //(2-1)*2
query.setMaxResults(2);
List resultList = query.getResultList();
resultList.forEach(p-> System.out.println("p = " + p));
}
/*
* 多条件查询
* */
@Test
public void show5(){
EntityManager entityManager = JpaUtil.getEntityManager();
//创建查询条件
Query query = entityManager.createQuery("from Customer where custName like ? and custIevel= ? ");
query.setParameter(1,"行健%");
query.setParameter(2,"VIP");
List resultList = query.getResultList();
resultList.forEach(o-> System.out.println("o = " + o));
}
/*
* 模糊查询
* */
@Test
public void show4(){
EntityManager entityManager = JpaUtil.getEntityManager();
//创建查询条件
Query query = entityManager.createQuery("from Customer where custName like ?");
// 对占位符赋值
query.setParameter(1,"行健%");
List resultList = query.getResultList();
resultList.forEach(p-> System.out.println("p = " + p));
}
/*
* 精确查询
* */
@Test
public void show3(){
EntityManager entityManager = JpaUtil.getEntityManager();
//创建查询条件
Query query = entityManager.createQuery("from Customer where custName= ?");
query.setParameter(1,"来了老弟");
List resultList = query.getResultList();
resultList.forEach(p-> System.out.println("p = " + p));
}
/*
* 排序
* */
@Test
public void show6(){
EntityManager entityManager = JpaUtil.getEntityManager();
Query query = entityManager.createQuery("from Customer where custName like ? order by custId desc");
query.setParameter(1,"行健%");
List resultList = query.getResultList();
resultList.forEach(o-> System.out.println("o = " + o));
}
/**
* 统计查询: 一行一列: 一个数字
*/
@Test
public void test5() {
EntityManager em = JpaUtil.getEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
//统计
/**
* select count(*) 约等于 count(1) mysql5.7之后
* select count(id)
* select count(1)
*/
Query query = em.createQuery("select avg(custId) from Customer where custName like ?");
//对占位符赋值
query.setParameter(1, "行健%");
//获取结果集
List<Double> list = query.getResultList();
//迭代
for (Double l : list) {
System.out.println("============================="+l);
}
}
<properties>
<spring.version>5.0.2.RELEASEspring.version>
<hibernate.version>5.0.7.Finalhibernate.version>
<slf4j.version>1.6.6slf4j.version>
<log4j.version>1.2.12log4j.version>
<c3p0.version>0.9.1.2c3p0.version>
<mysql.version>5.1.18mysql.version>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.6.8version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-coreartifactId>
<version>${hibernate.version}version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>${hibernate.version}version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>5.2.1.Finalversion>
dependency>
<dependency>
<groupId>c3p0groupId>
<artifactId>c3p0artifactId>
<version>${c3p0.version}version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>${log4j.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-jpaartifactId>
<version>1.9.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>javax.elgroupId>
<artifactId>javax.el-apiartifactId>
<version>2.2.4version>
dependency>
<dependency>
<groupId>org.glassfish.webgroupId>
<artifactId>javax.elartifactId>
<version>2.2.4version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.20version>
dependency>
dependencies>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="com.xjggb.pojo">property>
<property name="dataSource" ref="dataSource">property>
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider">bean>
property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false" />
<property name="database" value="MYSQL" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
<property name="showSql" value="true" />
bean>
property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect">bean>
property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">createprop>
props>
property>
bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver">property>
<property name="jdbcUrl" value="jdbc:mysql://192.168.93.222:3306/day19">property>
<property name="user" value="root">property>
<property name="password" value="root">property>
bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory">property>
bean>
<jpa:repositories base-package="com.xjggb.mapper" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager">jpa:repositories>
<context:component-scan base-package="com.xjggb">context:component-scan>
beans>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">createprop>
props>
property>
package com.xjggb.pojo;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name="cst_customer")
@Data
public class Customer implements Serializable {
@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 interface CustomerMapper extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> {
}
//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest {
@Autowired
private CustomerMapper customerMapper;
/*
* 查询一个对象
* */
@Test
public void show(){
Customer one = customerMapper.findOne(2L);
System.out.println("one = " + one);
}
}
//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest2 {
@Autowired
private CustomerMapper customerMapper;
/*
* 添加对象
* */
@Test
public void show(){
Customer customer = new Customer();
customer.setCustName("冰糖雪梨");
customer.setCustLevel("嘴强王者");
customerMapper.save(customer);
}
/*
* 删除数据
* */
@Test
public void show1(){
customerMapper.delete(4L);
}
/*
* 更新数据
* */
@Test
public void show3(){
//先查询在更新
Customer one = customerMapper.findOne(2L);
one.setCustName("我叫行健乖乖霸");
System.out.println("one = " + one);
customerMapper.save(one);
}
/*
* 查询全部数据
* */
@Test
public void show4(){
//查询全部数据
List<Customer> all = customerMapper.findAll();
all.forEach(p-> System.out.println("p = " + p));
}
}
/*
* 查询一个的两种方式
* */
@Test
@Transactional
public void show(){
// Customer one = customerMapper.findOne(3L);//立即加载
Customer one = customerMapper.getOne(3L);
System.out.println("one = " + one); //
}
/*
* 分页查询
* */
@Test
public void show2(){
/*
* 分页查询
* 参数一 当前页
* 参数二 页大小
* 参数三 排序对象 【可选】
* */
PageRequest pageRequest = new PageRequest(2,2);
//执行分页查询
Page<Customer> all = customerMapper.findAll(pageRequest);
System.out.println("获取总记录数 " + all.getTotalElements());
System.out.println("总页数" + all.getTotalPages());
List<Customer> content = all.getContent();
for (Customer customer : content) {
System.out.println("customer = " + customer);
}
}
/*
* 分页查询+排序查询
* */
@Test
public void show2(){
// 排序规则 倒叙
Sort orders = new Sort(Sort.Direction.DESC,"custId");
/*
* 分页查询
* 参数一 当前页
* 参数二 页大小
* 参数三 排序对象
* */
PageRequest pageRequest = new PageRequest(2,2,orders);
//执行分页查询
Page<Customer> all = customerMapper.findAll(pageRequest);
System.out.println("获取总记录数 " + all.getTotalElements());
System.out.println("总页数" + all.getTotalPages());
List<Customer> content = all.getContent();
for (Customer customer : content) {
System.out.println("customer = " + customer);
}
}
/*
* 统计所有\
* 相当于 select count(*) from 表
* */
@Test
public void show4(){
long count = customerMapper.count();
System.out.println("count = " + count);
}
/*
* 判断一个对象是否存在
* 存在为 true 不存在为 false
* 相当于 select * from 表 where id=?
* */
@Test
public void show3(){
boolean exists = customerMapper.exists(4L);
System.out.println("equals = " + exists);
}
掌握@Query注解
JPQL查询规则:
1)在dao接口中编写方法
2)在方法上使用@Query(value="JPQL语句")
3)返回值,自己定,如果是单个对象,你就写单个对象,如果多个,就用List
mapper代码
/*
* 精确查询
* */
@Query(value="from Customer where custName= ?")
Customer findJPQL1(String l);
/*
*模糊查询
* */
@Query(value="from Customer where custName like ?")
List<Customer> findListJPQL(String s);
/*
* 多条件查询
* 默认情况下:方法参数的所有与 占位符的索引一致,如果数据类型不一致,会报错
* 我们可以手动改变索引:只需要在占位符后面加上方法参数的索引即可
* */
@Query(value="from Customer where custId =?2 or custName like ?1")
List<Customer> findJPQL3(String o ,Long id);
测试
package com.xjggb.test;
import com.xjggb.mapper.CustomerMapper;
import com.xjggb.pojo.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest4 {
@Autowired
private CustomerMapper customerMapper;
/*
* 精确查询
* */
@Test
public void show2(){
Customer customer = customerMapper.findJPQL1("冰糖雪梨");
System.out.println("customer = " + customer);
}
/*
* 模糊查询
* */
@Test
public void show(){
List<Customer> listJPQL = customerMapper.findListJPQL("行健%");
listJPQL.forEach(u-> System.out.println("u = " + u));
System.out.println();
}
/*
*多条件查询
* */
@Test
public void show3(){
List<Customer> jpql3 = customerMapper.findJPQL3("行健%", 3L);
jpql3.forEach(o-> System.out.println("o = " + o));
System.out.println();
}
}
目标:掌握如何使用JPQL实现更新对象的操作
dao接口的要求:
1) 在Query的value属性中编写的update的jpql语句
2)dao接口的方法上还需要加入一个注解:@Modifying
测试的要求:
1)需要事务
2)在测试阶段,如果用的是spring的测试,执行成功之后就自动回滚了,看到效果,需要加注解:@Rollback(false)
mapper代码
/*
* 更新操作
* */
@Modifying //标记为更新操作
@Query(value="update Customer set custName=?2 where custId=?1")
void updateJPQL(Long id ,String nmae);
测试代码
/*
* 更新操作
* */
@Test
//由于我们现在用的Spring的测试,所以在测试成功之后,spring就给我们回滚了
//在测试阶段,如果想看到结果,需要加入另外一个注解,注意这个注解在非测试代码不用加
//TransactionRequiredException: Executing an update/delete query 事务异常
@Transactional
@Rollback(false)
public void show4(){
customerMapper.updateJPQL(2L,"隔壁老王");
}
sql查询规则
1)在dao接口中编写方法
2)在方法上使用@Query(value="SQL语句",nativeQuery=true)nativeQuery=true 开启sql语句查询
3)返回值,自己定,如果是单个对象,你就写单个对象,如果多个,就用List
mapper代码
/**
* sql查询
* nativeQuery=true 开启sql查询
*/
@Query(value="select * from cst_customer where cust_name like ?2 or cust_id = ?1",nativeQuery=true)
public List<Customer> findSQL(Long id, String name);
测试代码
/*
* sql查询
* */
@Test
public void show5(){
List<Customer> sql = customerMapper.findSQL(3L, "行健%");
sql.forEach(o-> System.out.println("o = " + o));
}
Dao接口的方法名规则:
1)以findBy开头
2)后面跟的是查询的属性条件: 属性名首字母大写
3)属性名后面跟的是查询规则: 模糊【Like】、精确 【不加规则代表精确查询】
4)多个条件以 And 、 Or 拼接
5)重复上面的步骤,从2开始
mapper接口
// 精确查询
Customer findByCustName(String name);
// 模糊查询
List<Customer> findByCustNameLike(String name);
// 多条件查询
List<Customer> findByCustNameOrCustId(String name , Long id);
测试
/*
* 多条件查询
* */
@Test
public void show8(){
List<Customer> p = customerMapper.findByCustNameOrCustId("冰糖雪梨", 8L);
p.forEach(o-> System.out.println("o = " + o));
}
/*
* 精确查询
* */
@Test
public void show7(){
Customer o = customerMapper.findByCustName("冰糖雪梨");
System.out.println("o = " + o);
}
/*
* 模糊查询
* */
@Test
public void show6(){
List<Customer> byCustNameLike = customerMapper.findByCustNameLike("行健%");
byCustNameLike.forEach(o->System.out.println("byCustNameLike = " + o));
}
规则的关键字:
Keyword | 方法名举例 | JPQL | ||
---|---|---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 | ||
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 | ||
Is,Equals | findByFirstnameIs, findByFirstnameEquals | … where x.firstname = ?1 | ||
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 | ||
LessThan | findByAgeLessThan | … where x.age < ?1 | ||
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 | ||
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 | ||
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 | ||
After | findByStartDateAfter | … where x.startDate > ?1 | ||
Before | findByStartDateBefore | … where x.startDate < ?1 | ||
IsNull | findByAgeIsNull | … where x.age is null | ||
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null | ||
Like | findByFirstnameLike | … where x.firstname like ?1 | ||
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 | ||
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) | ||
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) | ||
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) | ||
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc | ||
Not | findByLastnameNot | … where x.lastname <> ?1 | ||
In | findByAgeIn(Collection ages) | … where x.age in ?1 | ||
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 | ||
TRUE | findByActiveTrue() | … where x.active = true | ||
FALSE | findByActiveFalse() | … where x.active = false | ||
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
JpaSpecificationExecutor 接口 介绍:完成复杂查询和动态查询
JpaSpecificationExecutor<T> {
T findOne(Specification<T> spec);
List<T> findAll(Specification<T> spec);
Page<T> findAll(Specification<T> spec, Pageable pageable);
List<T> findAll(Specification<T> spec, Sort sort);
long count(Specification<T> spec);
}
Specification:它是一个接口,所有的动态拼接的条件都在这个接口的方法里完成
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}
它只有一个方法:toPredicate,此方法有三个参数
第一个:Root :获取对象的属性的
第二个:CriteriaQuery :查询的顶层接口,他可以完成自定义查询,一般不用
第三个:CriteriaBuilder :动态构建查询条件,都用它
//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest5 {
@Autowired
private CustomerMapper customerMapper;
/*
* 多条件查询
* */
@Test
public void show(){
Specification<Customer> spec = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cd) {
// 获取对比属性
Path<String> custName = root.get("custName");
Path<Object> custLevel = root.get("custLevel");
// 构建查询条件
Predicate like = cd.like(custName, "行健%");
Predicate equal = cd.equal(custLevel, "VIP");
// 合并查询条件
Predicate or = cd.or(like, equal);
return or;
}
};
List<Customer> all = customerMapper.findAll(spec);
all.forEach(o-> System.out.println("o = " + o));
}
}
/*
* 分页排序
* */
@Test
public void show2(){
// 相当于where
Specification<Customer> spec =null;
// 排序
Sort orders = new Sort(Sort.Direction.DESC,"custId");
// 分页
PageRequest pageRequest = new PageRequest(0, 2, orders);
Page<Customer> all = customerMapper.findAll(spec, pageRequest);
System.out.println("获取总记录数 " + all.getTotalElements());
System.out.println("获取页数" + all.getTotalPages());
all.getContent().forEach(o-> System.out.println("o = " + o));
}
使用带入法 一对多
客户表 : 一方 一个客户可一有多个联系人
联系人表 : 多方 一个联系只能属于一家公司
找主外键
多方【从表】:外键在多方中
一方【主表】:外键的值来源于一方的主键
在实体类中描述他们的关系
类类与类的关系 :继承和包含
我们才用包含
客户包含多个联系人 :List / Set
联系人包含一个联系人 Customer
客户实体类代码
package com.xjggb.pojo;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name="cst_customer")
@Data
public class Customer implements Serializable {
@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;
//当前是一方
/**
* new :
* 1、如果new出当前方法,集合也会实例化
* 2、我们为了解决有可能出现的空指针异常,new,我们可以在new的时候指定开辟的大小
*
* 不new:
* 容器用来装联系人实体
* customer.getLinkman().add(new Linkman())
* 有可能出现空指针异常
*
*/
// 配置一对多关系注解
//配置一对多
@OneToMany(targetEntity = Linkman.class)
// 配置外键注解
@JoinColumn(
// 外键名称
name = "lkm_cust_id",
// 外键值的来源:来源于主表的主键
referencedColumnName = "cust_id"
)
private Set<Linkman> linkmen=new HashSet<>(0);
}
Linkman联系人实体类
package com.xjggb.pojo;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "cst_linkman")
@Data
public class Linkman implements Serializable {
@Id
@Column(name="lkm_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long lkmId;
@Column(name="lkm_name")
private String lkmName;
@Column(name="lkm_gender")
private String lkmGender;
@Column(name="lkm_phone")
private String lkmPhone;
@Column(name="lkm_mobile")
private String lkmMobile;
@Column(name="lkm_email")
private String lkmEmail;
@Column(name="lkm_position")
private String lkmPosition;
@Column(name="lkm_memo")
private String lkmMemo;
//当前是多方
// 关系注解 多对一
@ManyToOne(targetEntity = Customer.class)
// 外键注解
@JoinColumn(
// 外键名称
name = "lkm_cust_id",
// 外键值的来源:来源于主表的主键
referencedColumnName = "cust_id"
)
private Customer customer;
}
package com.xjggb.test;
import com.xjggb.mapper.CustomerMapper;
import com.xjggb.mapper.LinkmanMapper;
import com.xjggb.pojo.Customer;
import com.xjggb.pojo.Linkman;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest6 {
@Autowired
private CustomerMapper customerMapper;
@Autowired
private LinkmanMapper linkmanMapper;
/**
* 单向保存:
* 一对多的保存原则: 先保存主表的数据,再保存从表的数据
*/
@Test
@Transactional
@Rollback(false)
public void show(){
Customer customer = new Customer();
customer.setCustName("行健乖乖把");
Linkman linkman = new Linkman();
linkman.setLkmName("吾乃行健乖乖把");
linkman.setLkmPosition("CEO");
//要想外键有值,必须配置关系:
//1、让客户来维护关系: 客户通过update的语句来维护外键
// customer.getLinkmen().add(linkman);
//2、让联系人维护外键: 联系人通过insert语句就可以维护外键【让联系人维护外键的效率高,少了update的语句】
linkman.setCustomer(customer);
//保存:先保存主表的数据,再保存从表的数据
// 保存主表的数据,在保存从表的数
customerMapper.save(customer);
linkmanMapper.save(linkman);
}
}
分析
如果是双向保存,会有两条insert 和 一条update
原因:多出的这一条update语句,是由于客户维护外键导致的
解决:
不想看到多出的这一条update的语句
让客户不维护外键就可以
删除@JoinColumn注解
package com.xjggb.pojo;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
/**
* 实体类
* @author Johnny.Chen
*
*/
@Entity
@Table(name="cst_customer")
public class Customer implements Serializable{
@Id
@Column(name="cust_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
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;
//当前是一方
/**
* new :
* 1、如果new出当前方法,集合也会实例化
* 2、我们为了解决有可能出现的空指针异常,new,我们可以在new的时候指定开辟的大小
*
* 不new:
* 容器用来装联系人实体
* customer.getLinkman().add(new Linkman())
* 有可能出现空指针异常
*
*/
//配置一对多的关系注解
//客户维护外键
/*//1、关系注解:一对多
@OneToMany(targetEntity=Linkman.class)
//2、外键注解
@JoinColumn(
//外键名称
name="lkm_cust_id",
//外键值的来源: 来源于主表的主键
referencedColumnName="cust_id"
)*/
//客户不维护外键
@OneToMany(mappedBy="customer")//mappedBy: 配置的对方有@JoinColumn注解的属性的名称
private Set<Linkman> linkmans = new HashSet<>(0);
/**
* 获取
* @return custId
*/
public Long getCustId() {
return custId;
}
/**
* 设置
* @param custId
*/
public void setCustId(Long custId) {
this.custId = custId;
}
/**
* 获取
* @return custName
*/
public String getCustName() {
return custName;
}
/**
* 设置
* @param custName
*/
public void setCustName(String custName) {
this.custName = custName;
}
/**
* 获取
* @return custSource
*/
public String getCustSource() {
return custSource;
}
/**
* 设置
* @param custSource
*/
public void setCustSource(String custSource) {
this.custSource = custSource;
}
/**
* 获取
* @return custLevel
*/
public String getCustLevel() {
return custLevel;
}
/**
* 设置
* @param custLevel
*/
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
/**
* 获取
* @return custIndustry
*/
public String getCustIndustry() {
return custIndustry;
}
/**
* 设置
* @param custIndustry
*/
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
/**
* 获取
* @return custPhone
*/
public String getCustPhone() {
return custPhone;
}
/**
* 设置
* @param custPhone
*/
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
/**
* 获取
* @return custAddress
*/
public String getCustAddress() {
return custAddress;
}
/**
* 设置
* @param custAddress
*/
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
/**
* 获取
* @return linkmans
*/
public Set<Linkman> getLinkmans() {
return linkmans;
}
/**
* 设置
* @param linkmans
*/
public void setLinkmans(Set<Linkman> linkmans) {
this.linkmans = linkmans;
}
}
package com.xjggb.pojo;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
/**
* 联系人
* @author Johnny.Chen
*
*/
@Entity
@Table(name="cst_linkman")
public class Linkman implements Serializable{
@Id
@Column(name="lkm_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long lkmId;
@Column(name="lkm_name")
private String lkmName;
@Column(name="lkm_gender")
private String lkmGender;
@Column(name="lkm_phone")
private String lkmPhone;
@Column(name="lkm_mobile")
private String lkmMobile;
@Column(name="lkm_email")
private String lkmEmail;
@Column(name="lkm_position")
private String lkmPosition;
@Column(name="lkm_memo")
private String lkmMemo;
//当前是多方
//1、关系注解:多对一
@ManyToOne(targetEntity=Customer.class)
//2、外键注解
@JoinColumn(
//外键名称
name="lkm_cust_id",
//外键值的来源: 来源于主表的主键
referencedColumnName="cust_id"
)
private Customer customer;
/**
* 获取
* @return lkmId
*/
public Long getLkmId() {
return lkmId;
}
/**
* 设置
* @param lkmId
*/
public void setLkmId(Long lkmId) {
this.lkmId = lkmId;
}
/**
* 获取
* @return lkmName
*/
public String getLkmName() {
return lkmName;
}
/**
* 设置
* @param lkmName
*/
public void setLkmName(String lkmName) {
this.lkmName = lkmName;
}
/**
* 获取
* @return lkmGender
*/
public String getLkmGender() {
return lkmGender;
}
/**
* 设置
* @param lkmGender
*/
public void setLkmGender(String lkmGender) {
this.lkmGender = lkmGender;
}
/**
* 获取
* @return lkmPhone
*/
public String getLkmPhone() {
return lkmPhone;
}
/**
* 设置
* @param lkmPhone
*/
public void setLkmPhone(String lkmPhone) {
this.lkmPhone = lkmPhone;
}
/**
* 获取
* @return lkmMobile
*/
public String getLkmMobile() {
return lkmMobile;
}
/**
* 设置
* @param lkmMobile
*/
public void setLkmMobile(String lkmMobile) {
this.lkmMobile = lkmMobile;
}
/**
* 获取
* @return lkmEmail
*/
public String getLkmEmail() {
return lkmEmail;
}
/**
* 设置
* @param lkmEmail
*/
public void setLkmEmail(String lkmEmail) {
this.lkmEmail = lkmEmail;
}
/**
* 获取
* @return lkmPosition
*/
public String getLkmPosition() {
return lkmPosition;
}
/**
* 设置
* @param lkmPosition
*/
public void setLkmPosition(String lkmPosition) {
this.lkmPosition = lkmPosition;
}
/**
* 获取
* @return lkmMemo
*/
public String getLkmMemo() {
return lkmMemo;
}
/**
* 设置
* @param lkmMemo
*/
public void setLkmMemo(String lkmMemo) {
this.lkmMemo = lkmMemo;
}
/**
* 获取
* @return customer
*/
public Customer getCustomer() {
return customer;
}
/**
* 设置
* @param customer
*/
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
package com.xjggb.test;
import com.xjggb.mapper.CustomerMapper;
import com.xjggb.mapper.LinkmanMapper;
import com.xjggb.pojo.Customer;
import com.xjggb.pojo.Linkman;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest6 {
@Autowired
private CustomerMapper customerMapper;
@Autowired
private LinkmanMapper linkmanMapper;
/*
* 双向绑定
* */
/**
* 双向保存:
* 一对多的保存原则: 先保存主表的数据,再保存从表的数据
*
* 你知道我,我也知道你
*/
@Test
//为了解决异常:先加入事务
@Transactional
//由于在测试阶段,spring会回滚
@Rollback(false)
public void test() {
Customer c = new Customer();
c.setCustName("赤木钢化玻璃公司");
Linkman l = new Linkman();
l.setLkmName("晴子");
l.setLkmPosition("CEO");
//要想外键有值,必须配置关系:双向
c.getLinkmans().add(l);
l.setCustomer(c);
//保存:先保存主表的数据,再保存从表的数据
customerMapper.save(c);
linkmanMapper.save(l);
}
}
1)没有从表数据引用:随便删
2)有从表数据
a、在默认情况【双方维护外键】下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表结构上,外键字段有非空约束,默认情况就会报错了。
b、如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null,没有关系)因为在删除时,它根本不会去更新从表的外键字段了。
c、如果还想删除,使用级联删除引用
package com.xjggb.pojo;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
/**
* 实体类
* @author Johnny.Chen
*
*/
@Entity
@Table(name="cst_customer")
public class Customer implements Serializable{
@Id
@Column(name="cust_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
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;
//当前是一方
/**
* new :
* 1、如果new出当前方法,集合也会实例化
* 2、我们为了解决有可能出现的空指针异常,new,我们可以在new的时候指定开辟的大小
*
* 不new:
* 容器用来装联系人实体
* customer.getLinkman().add(new Linkman())
* 有可能出现空指针异常
*
*/
//配置一对多的关系注解
//客户维护外键
/*//1、关系注解:一对多
@OneToMany(targetEntity=Linkman.class)
//2、外键注解
@JoinColumn(
//外键名称
name="lkm_cust_id",
//外键值的来源: 来源于主表的主键
referencedColumnName="cust_id"
)*/
//客户不维护外键
@OneToMany(
mappedBy="customer",//mappedBy: 配置的对方有@JoinColumn注解的属性的名称
cascade = CascadeType.ALL//级联保存更新删除
)
private Set<Linkman> linkmans = new HashSet<>(0);
/**
* 获取
* @return custId
*/
public Long getCustId() {
return custId;
}
/**
* 设置
* @param custId
*/
public void setCustId(Long custId) {
this.custId = custId;
}
/**
* 获取
* @return custName
*/
public String getCustName() {
return custName;
}
/**
* 设置
* @param custName
*/
public void setCustName(String custName) {
this.custName = custName;
}
/**
* 获取
* @return custSource
*/
public String getCustSource() {
return custSource;
}
/**
* 设置
* @param custSource
*/
public void setCustSource(String custSource) {
this.custSource = custSource;
}
/**
* 获取
* @return custLevel
*/
public String getCustLevel() {
return custLevel;
}
/**
* 设置
* @param custLevel
*/
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
/**
* 获取
* @return custIndustry
*/
public String getCustIndustry() {
return custIndustry;
}
/**
* 设置
* @param custIndustry
*/
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
/**
* 获取
* @return custPhone
*/
public String getCustPhone() {
return custPhone;
}
/**
* 设置
* @param custPhone
*/
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
/**
* 获取
* @return custAddress
*/
public String getCustAddress() {
return custAddress;
}
/**
* 设置
* @param custAddress
*/
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
/**
* 获取
* @return linkmans
*/
public Set<Linkman> getLinkmans() {
return linkmans;
}
/**
* 设置
* @param linkmans
*/
public void setLinkmans(Set<Linkman> linkmans) {
this.linkmans = linkmans;
}
public String toString() {
return "Customer{custId = " + custId + ", custName = " + custName + ", custSource = " + custSource + ", custLevel = " + custLevel + ", custIndustry = " + custIndustry + ", custPhone = " + custPhone + ", custAddress = " + custAddress + ", linkmans = " + linkmans + "}";
}
}
package com.xjggb.test;
import com.xjggb.mapper.CustomerMapper;
import com.xjggb.pojo.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest7 {
@Autowired
private CustomerMapper customerMapper;
@Test
@Transactional
@Rollback(false)
public void show(){
//a、在默认情况【双方维护外键】下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表结构上,外键字段有非空约束,默认情况就会报错了。
//b、如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null,没有关系)因为在删除时,它根本不会去更新从表的外键字段了。
//c、如果还想删除,使用级联删除引用
/**
* 级联操作:
* 我们操作一个对象的时候,让代码在后台偷偷的去操作关联的另外一个对象
* 级联删除:
* 我们删除客户的时候,让代码先把它关联的联系人属性删除,然后再删除主表数据
*
* 配置级联:【慎用】【株连九族】
* 1、我们操作谁就在谁哪里配置级联,我们现在删除的是客户,所以在客户哪里配置
* 2、在关系注解中配置级联:
* @OneToMany(cascade=CascadeType.ALL) 级联保存更新删除
* @OneToMany(cascade=CascadeType.PERSIST) 级联保存
* @OneToMany(cascade=CascadeType.MERGE) 级联更新
* @OneToMany(cascade=CascadeType.REMOVE) 级联删除
*
*/
customerMapper.delete(1L);
}
}
小结
1、关系注解:
@OneToMany(mappedBy=“对方有@JoinColumn注解的属性名称”,targeEntity="",cascade="")
@ManyToOne(targeEntity="",cascade="") //不能配置mappedBy,自己不能放弃自己的外键维护
2、维护外键注解:谁有它谁就能维护外键
@JoinColumn(name=“外键名称”,referenceColumnName=“主表的主键名称”)
3、操作:save和delete
关键点找外键
用户:一个用户可以多个角色
角色:可以拥有多个用户
多对多关系
找出中间表
用户表
角色表
用户角色的中间表,两列,来源用户表的与角色表主键,联合主键
一个用户包含多个角色 :
一个角色包含多个用户:
用户实体类
package com.xjggb.pojo;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
/**
*
* @author Johnny.Chen
*
*/
@Entity
//@Table(name="User") //如果表名和类名一样,可以省略
public class User implements Serializable {
@Id
//@Column(name="userId") //如果字段名和属性名一样,可以省略
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer userId;
private String name;
private String age;
private String pwd;
//一个用户包含多个角色
// 关系注解配置多对多
@ManyToMany(targetEntity = Role.class)
// 维护中间表注解
@JoinTable(
name = "T_user_Role_Ref" , //中间表名称
// 当前中间表的外键
joinColumns = @JoinColumn(name = "u_id",referencedColumnName = "userId"),
// 对方在中间表的外键
inverseJoinColumns = @JoinColumn(name = "r_id",referencedColumnName = "roleId")
)
private Set<Role> roles = new HashSet<>(0);
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User [userId=" + userId + ", name=" + name + ", age=" + age + ", pwd=" + pwd + "]";
}
}
角色类
package com.xjggb.pojo;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
public class Role {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer roleId;
private String roleName;
//
// //一个角色包含多个用户
// @ManyToMany(targetEntity =User.class )
维护中间表注解
// @JoinTable(
// name = "T_user_Role_Ref" , //中间表名称
当前中间表的外键
// joinColumns = @JoinColumn(name = "r_id",referencedColumnName = "roleId"),
对方在中间表的外键
// inverseJoinColumns = @JoinColumn(name = "u_id",referencedColumnName = "userId")
@ManyToMany(
mappedBy = "roles",
cascade = CascadeType.ALL //级联操作
)
private Set<User> users = new HashSet<>(0);
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
@Override
public String toString() {
return "Role [roleId=" + roleId + ", roleName=" + roleName + "]";
}
}
测试
package com.xjggb.test;
import com.xjggb.mapper.CustomerMapper;
import com.xjggb.mapper.RoleMapper;
import com.xjggb.mapper.UserMapper;
import com.xjggb.pojo.Customer;
import com.xjggb.pojo.Role;
import com.xjggb.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest8 {
@Autowired
private UserMapper userMapper;
@Autowired
private RoleMapper roleMapper;
/*
*
* */
@Test
@Transactional
@Rollback(false)
public void show(){
User user = new User();
user.setName("三井寿");
Role role = new Role();
role.setRoleName("牙医");
// 谁放弃都可以只能一张表维护中间表 不然会报错 Duplicate entry '1-1' for key 'PRIMARY'
role.getUsers().add(user);
user.getRoles().add(role);
userMapper.save(user);
roleMapper.save(role);
}
}
实体类
package com.xjggb.pojo;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
public class Role {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer roleId;
private String roleName;
//
// //一个角色包含多个用户
// @ManyToMany(targetEntity =User.class )
维护中间表注解
// @JoinTable(
// name = "T_user_Role_Ref" , //中间表名称
当前中间表的外键
// joinColumns = @JoinColumn(name = "r_id",referencedColumnName = "roleId"),
对方在中间表的外键
// inverseJoinColumns = @JoinColumn(name = "u_id",referencedColumnName = "userId")
@ManyToMany(
mappedBy = "roles",
cascade = CascadeType.ALL //级联操作
)
private Set<User> users = new HashSet<>(0);
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
@Override
public String toString() {
return "Role [roleId=" + roleId + ", roleName=" + roleName + "]";
}
}
测试
package com.xjggb.test;
import com.xjggb.mapper.CustomerMapper;
import com.xjggb.mapper.RoleMapper;
import com.xjggb.mapper.UserMapper;
import com.xjggb.pojo.Customer;
import com.xjggb.pojo.Role;
import com.xjggb.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest8 {
@Autowired
private UserMapper userMapper;
@Autowired
private RoleMapper roleMapper;
/**
* 删除
*/
@Test
//为了解决异常:先加入事务
@Transactional
//由于在测试阶段,spring会回滚
@Rollback(false)
public void test3() {
//roleDao.delete(1); //如果已经配置了放弃中间表的维护,删除不了
/**
* 级联:
* 1)单向级联:
* 2)双向级联:两边的关系注解都配置级联【禁用】【寸草不生】
*/
roleMapper.delete(1); //如果已经配置了放弃中间表的维护,默认删除不了,如果配置了级联可以删除
//工作中:先删除用户,再删除角色
/*userDao.delete(1);
roleDao.delete(1);*/
}
/*
*
* */
@Test
@Transactional
@Rollback(false)
public void show(){
User user = new User();
user.setName("三井寿");
Role role = new Role();
role.setRoleName("牙医");
// 谁放弃都可以只能一张表维护中间表 不然会报错 Duplicate entry '1-1' for key 'PRIMARY'
role.getUsers().add(user);
user.getRoles().add(role);
userMapper.save(user);
roleMapper.save(role);
}
}
对象导航查询: 通过对象打点的时候,调用管理属性查询
1)通过客户导航查询联系人:customer.getLinkmen() :
2)联系人导航查询客户:linkman.getCustomer()
//客户不维护外键
@OneToMany(
mappedBy="customer",//mappedBy: 配置的对方有@JoinColumn注解的属性的名称
cascade = CascadeType.ALL//级联保存更新删除
,fetch = FetchType.EAGER //配置立即加载 LAZY 懒加载 EAGER 立即加载
)
代码如下
@Test
//为了解决异常:先加入事务
@Transactional
//由于在测试阶段,spring会回滚
@Rollback(false)
public void show(){
//通过联系人导航查询客户 默认延迟加载
//通过客户导航查询联系人:懒加载
Customer one = customerMapper.findOne(1L);//先查客户
System.out.println("one = " + one);
Set<Linkman> linkmans = one.getLinkmans();//再查联系人
//迭代
for (Linkman linkman : linkmans) {
System.out.println(linkman);
}
}
对jpa的入门 CRUD
jpa工具的抽取
接口方法的定义查询
Specification 查询的使用
一对多查询的映射
多对多的映射