相同处:
1.都跟数据库操作有关,JPA是jdbc的升华,升级版。
2.JDBC和JPA都是一组规范1接口。
3.都是由SUN公司推出的
不同处:
1.JDBC是有各个关系型数据库实现的,JPA是有ORM框架实现。
2.JDBC使用SQL语句和数据库通信,JPA用面向对象方式,通过ORM框架生成SQL,进行操作。
3.JPA在JDBC之上,JPA也要依赖JDBC才能操作数据库。
mybatis:小巧、方便、高效、简单、直接、半自动
半自动的ORM框架
小巧:mybatis就是jdbc封装
在国内流行
场景:在业务比较复杂的系统进行使用
hibernate:强大、方便、高效、复杂、绕弯子、全自动
全自动的ORM框架
强大:根据ORM映射生成sql
在国外流行
场景:在业务相对简单的系统进行使用,随着微服务流行。
pom.xml
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>5.4.32.Finalversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.30version>
dependency>
dependencies>
实体类
package com.llg.pojo;
import lombok.Data;
import javax.persistence.*;
/**
* 实体类
*
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 10:50
*/
@Entity // 作为hibernate 实体类
@Table(name = "cst_customer") // 映射的表名
@Data
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_address")
private String custAddress;
}
hibernate.cfg.xml
DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.username">rootproperty>
<property name="connection.password">rootproperty>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driverproperty>
<property name="connection.url">jdbc:mysql:///springdata_jpaproperty>
<property name="dialect">org.hibernate.dialect.MySQL8Dialectproperty>
<property name="show_sql">trueproperty>
<property name="format_sql">trueproperty>
<property name="hbm2ddl.auto">updateproperty>
<property name="connection.isolation">2property>
<property name="use_identifier_rollback">trueproperty>
<mapping class="com.llg.pojo.Customer">mapping>
session-factory>
hibernate-configuration>
单元测试
package com.llg.test;
import com.llg.pojo.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 11:23
*/
public class HibernateTest {
// Session 工厂 :数据库会话 代码持久化操作数据库的一个桥梁
private SessionFactory sf;
@Before
public void init(){
StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure("/hibernate.cfg.xml").build();
sf = new MetadataSources(registry).buildMetadata().buildSessionFactory();
}
@Test
public void testC(){
// session进行持久化操作
try(Session session = sf.openSession()){
// 开启事务
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCustName("刘列广");
session.save(customer);
transaction.commit();
}
}
@Test
public void testR(){
// session进行持久化操作
try(Session session = sf.openSession()){
// 开启事务
Transaction transaction = session.beginTransaction();
Customer customer = session.find(Customer.class,1L);
System.out.println("customer = " + customer);
transaction.commit();
}
}
@Test
public void testR_lazy(){
// session进行持久化操作
try(Session session = sf.openSession()){
// 开启事务
Transaction transaction = session.beginTransaction();
Customer customer = session.load(Customer.class,1L);
System.out.println("==========================");
System.out.println("customer = " + customer);
transaction.commit();
}
}
@Test
public void testU() {
// session进行持久化操作
try (Session session = sf.openSession()) {
// 开启事务
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCustName("刘列广1");
customer.setCustId(1L);
session.update(customer);
// session.saveOrUpdate(customer);
transaction.commit();
}
}
@Test
public void testD(){
// session进行持久化操作
try(Session session = sf.openSession()){
// 开启事务
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCustId(1L);
session.remove(customer);
// session.saveOrUpdate(customer);
transaction.commit();
}
}
@Test
public void testR_HQL(){
// session进行持久化操作
try(Session session = sf.openSession()){
// 开启事务
Transaction transaction = session.beginTransaction();
String hql = " FROM Customer where custId=:id";
List<Customer> resultList = session.createQuery(hql, Customer.class).setParameter("id", 1L).getResultList();
System.out.println("resultList = " + resultList);
transaction.commit();
}
}
}
如果单独使用hibernate的api来进行持久化操作,则不能随意切换其他ORM框架
JPA示例
1.添加META-INF\persistence.xml
<persistence version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit
name="hibernateJPA"
transaction-type="RESOURCE_LOCAL">
<description>
Hypersistence Optimizer is a dynamic analyzing tool that can scan
your JPA and Hibernate application and provide you tips about the
changes you need to make to entity mappings, configurations, queries,
and Persistence Context actions to speed up your data access layer.
description>
<provider>org.hibernate.jpa.HibernatePersistenceProviderprovider>
<class>com.llg.pojo.Customerclass>
<properties>
<property
name="javax.persistence.jdbc.driver"
value="com.mysql.cj.jdbc.Driver"
/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///springdata_jpa"
/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="dialect" value="org.hibernate.dialect.MySQL8Dialect"/>
properties>
persistence-unit>
persistence>
jpa的单元测试
package com.llg.test;
import com.llg.pojo.Customer;
import org.junit.Before;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 13:34
*/
public class JpaTest {
EntityManagerFactory factory;
@Before
public void init() {
factory = Persistence.createEntityManagerFactory("hibernateJPA");
}
@Test
public void testC(){
EntityManager em = factory.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Customer customer = new Customer();
customer.setCustName("张三");
customer.setCustAddress("长沙");
em.persist(customer);
tx.commit();
}
@Test
public void testR(){
EntityManager em = factory.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Customer customer = em.find(Customer.class, 3L);
System.out.println("=========================");
System.out.println("customer = " + customer);
tx.commit();
}
@Test
public void testR_lazy(){
EntityManager em = factory.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Customer customer = em.getReference(Customer.class, 3L);
System.out.println("=========================");
System.out.println("customer = " + customer);
tx.commit();
}
@Test
public void testU(){
EntityManager em = factory.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Customer customer = new Customer();
customer.setCustName("张三");
// customer.setCustAddress("长沙");
customer.setCustId(3L);
/**
* 如果指定主键:
* 更新: 先查询 看是否变化
* 有变化更新,如果没有变化就不更新
* 如果没有指定主键:
* 插入
*/
em.merge(customer);
tx.commit();
}
@Test
public void testU_JPQL(){
EntityManager em = factory.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
String jpql = "update Customer set custName=:name where custId=:id";
em.createQuery(jpql)
.setParameter("name","李四")
.setParameter("id",1L)
.executeUpdate();
tx.commit();
}
@Test
public void testU_SQL(){
EntityManager em = factory.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
String sql = "update cst_customer set cust_name=:name where cust_id=:id";
em.createNativeQuery(sql)
.setParameter("name","王五")
.setParameter("id",2L)
.executeUpdate();
tx.commit();
}
@Test
public void testD(){
EntityManager em = factory.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Customer customer = em.find(Customer.class, 3L);
em.remove(customer);
tx.commit();
}
}
我们来实现一个基于Spring Data JPA的示例感受一下和之前单独使用的区别:
依赖
1.最好在父maven项目中设置spring data统一版本管理依赖: 因为不同的spring data子项目发布时间版本不一样,你自己维护很麻烦, 这样不同的spring data子项目能保证是统一版本.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring‐data‐bomartifactId>
<version>2020.0.14version>
<scope>importscope>
<type>pomtype>
dependency>
dependencies>
dependencyManagement>
2.在子项目中添加:
<dependencies>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-jpaartifactId>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>5.4.32.Finalversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.30version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.8version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.3.3version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.28version>
dependency>
dependencies>
pojo
package com.llg.pojo;
import lombok.Data;
import javax.persistence.*;
/**
* 实体类
*
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 10:50
*/
@Entity // 作为hibernate 实体类
@Table(name = "cst_customer") // 映射的表名
@Data
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_address")
private String custAddress;
}
spring.xml
SpringDataJPAConfig方式
package com.llg.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 17:07
*/
@Configuration
@EnableJpaRepositories("com.llg.repositories")
@EnableTransactionManagement
public class SpringDataJPAConfig {
/**
* 数据源
* @return DataSource
*/
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/springdata_jpa");
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.llg.pojo");
factory.setDataSource(dataSource());
return factory;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
测试
package com.llg.test;
import com.llg.config.SpringDataJPAConfig;
import com.llg.pojo.Customer;
import com.llg.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.Optional;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 16:49
*/
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class JpaTest {
@Resource
CustomerRepository repository;
@Test
public void testR(){
Optional<Customer> customer = repository.findById(1L);
System.out.println(customer.get());
}
@Test
public void testC(){
Customer customer = new Customer();
customer.setCustName("lllg");
repository.save(customer);
}
@Test
public void testD(){
Customer customer = new Customer();
customer.setCustId(2L);
repository.delete(customer);
}
}
使用 Spring Data Repositories
Spring Data repository 抽象的目标是显着减少为各种持久性存储实现数据访问层所需的样板代码量。
CrudRepository
// 用来插入和修改 有主键就修改,没有主键就是新增
// 获得插入后自增id,获取返回值
<S extends T> S save(S entity);
// 通过集合保存多个实体
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
// 通过主键查询实体
Optional<T> findById(ID id);
// 通过主键查询是否存在 返回boolean
boolean existsById(ID id);
// 查询所有
Iterable<T> findAll();
// 通过集合的主键 查询多个实体,, 返回集合
Iterable<T> findAllById(Iterable<ID> ids);
// 查询总数量
long count();
// // 根据id进行删除
void deleteById(ID id);
// 根据实体进行删除
void delete(T entity);
// 删除多个
void deleteAllById(Iterable<? extends ID> ids);
// 删除多个传入集合实体
void deleteAll(Iterable<? extends T> entities);
// 删除所有
void deleteAll();
在 之上CrudRepository,有一个PagingAndSortingRepository抽象,它添加了额外的方法来简化对实体的分页访问
@Test
public void testPage(){
Page page = repository.findAll(PageRequest.of(0, 2));
System.out.println("getTotalPages = " + page.getTotalPages());
System.out.println("getTotalPages = " + page.getTotalPages());
System.out.println("getContent = " + page.getContent());
}
@Test
public void testSort(){
Sort sort = Sort.by("custId").descending();
Iterable all = repository.findAll(sort);
System.out.println("all = " + all);
}
@Test
public void testSortTypeSafe(){
Sort.TypedSort sortType = Sort.sort(Customer.class);
Sort sort = sortType.by(Customer::getCustId).descending();
Iterable all = repository.findAll(sort);
System.out.println("all = " + all);
}
@Query
查询如果返回单个实体 就用pojo接收 , 如果是多个需要通过集合
参数设置方式
增删改:
@Transactional // 通常会放在业务逻辑层上面去声明
@Modifying // 通知springdatajpa 是增删改的操作
测试
package com.llg.repositories;
import com.llg.pojo.Customer;
import org.hibernate.annotations.Table;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 16:48
*/
@Repository
public interface CustomerRepository extends PagingAndSortingRepository<Customer,Long> {
// 增删查改
// 查询
// @Query("from Customer where custName=?1")
// Customer findCustomerByCustName(String custName);
// 查询
@Query("from Customer where custName=:custName")
List<Customer> findCustomerByCustName(@Param("custName") String custName);
// 修改
@Transactional // 事务
@Modifying // 通知springdatajpa 是增删改操作
@Query("update Customer c set c.custName=:custName where c.custId=:id")
int updateCustomer(@Param("custName") String custName,@Param("id") Long id);
// 删除
@Transactional // 事务
@Modifying // 通知springdatajpa 是增删改操作
@Query("delete from Customer c where c.custId=:id")
int deleteCustomer(@Param("id") Long id);
// 新增
@Transactional // 事务
@Modifying // 通知springdatajpa 是增删改操作
@Query("insert into Customer(custName) select c.custName from Customer c where c.custId=?1")
int insertCustomerBySelect(@Param("id") Long id);
// 原生sql
@Query(value = "select * from cst_customer where cust_name=:custName",nativeQuery = true)
List<Customer> findCustomerByCustNameBySql(@Param("custName") String custName);
}
package com.llg.test;
import com.llg.config.SpringDataJPAConfig;
import com.llg.pojo.Customer;
import com.llg.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.List;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 18:20
*/
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class JpqlTest {
@Resource
CustomerRepository repository;
@Test
public void findCustomerByCustName(){
List<Customer> customerByCustName = repository.findCustomerByCustName("王");
System.out.println("customerByCustName = " + customerByCustName);
}
@Test
public void updateCustomer(){
int i = repository.updateCustomer("浏览量", 4L);
System.out.println("updateCustomer = " + i);
}
@Test
public void insertCustomerBySelect(){
int i = repository.insertCustomerBySelect( 4L);
System.out.println("updateCustomer = " + i);
}
@Test
public void findCustomerByCustNameBySql(){
List<Customer> customerByCustName = repository.findCustomerByCustNameBySql("王五");
System.out.println("customerByCustName = " + customerByCustName);
}
}
支持的查询方法主题关键字(前缀)
**决定当前方法作用**
只支持查询和删除
如:
查询类型:findBy ,readBy,getBy, queryBy, searchBy streamBy
判断是否存在类型:existsBy
计数:countBy
删除查询:deleteBy , removeBy
限制查询结果:First top 放在find和by之间
去重返回:Distinct
支持的查询方法谓词关键字和修饰符
**决定查询条件**
Distinct 示例:findDistinctByName
And 示例:findByNameAndAge
Or
Is,Equals
Between
LessThan <
LessThanEqual <=
GreaterThan >
GreaterThanEqual >=
After 日期之前
Before 日期之后
IsNull,Null
IsNotNull,NotNull
Like
NotLike
StartingWith 前模糊
EndingWith 后模糊
OrderBy
Not
In
NotIn
True
False
IgoreCase
测试规定方法名使用
package com.llg.repositories;
import com.llg.pojo.Customer;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.query.QueryByExampleExecutor;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 16:48
*/
@Repository
public interface CustomeMethodNamerRepository extends PagingAndSortingRepository<Customer,Long> {
List<Customer> findByCustName(String custName);
Boolean existsByCustName(String custName);
@Transactional
@Modifying
int deleteByCustName(String custName);
List<Customer> findByCustNameLike(String custName);
}
单元测试
package com.llg.test;
import com.llg.config.SpringDataJPAConfig;
import com.llg.pojo.Customer;
import com.llg.repositories.CustomeMethodNamerRepository;
import com.llg.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.List;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 18:20
*/
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class MethondNameTest {
@Resource
CustomeMethodNamerRepository repository;
@Test
public void findByCustName(){
List customerByCustName = repository.findByCustName("浏览量");
System.out.println("customerByCustName = " + customerByCustName);
}
@Test
public void existsByCustName(){
Boolean customerByCustName = repository.existsByCustName("浏览量");
System.out.println("customerByCustName = " + customerByCustName);
}
@Test
public void deleteByCustName(){
int deleteByCustName = repository.deleteByCustName("浏览量");
System.out.println("deleteByCustName = " + deleteByCustName);
}
@Test
public void findByCustNameLike(){
List findByCustNameLike = repository.findByCustNameLike("%四");
System.out.println("findByCustNameLike = " + findByCustNameLike);
}
}
只支持查询
不支持嵌套或分组的属性约束,如 firstname = ?0 or (firstname = ?1 and lastname = ?2).
只支持字符串 start/contains/ends/regex 匹配和其他属性类型的精确匹配。
仅支持字符串的 开始、结束、包含、正则匹配 , 其他类型的精确匹配。
实现:
1.将Repository继承QueryByExampleExecutor
package com.llg.repositories;
import com.llg.pojo.Customer;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.query.QueryByExampleExecutor;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 16:48
*/
@Repository
public interface CustomerRepositoryQueryByExample extends PagingAndSortingRepository<Customer,Long>, QueryByExampleExecutor<Customer> {
}
测试用例
package com.llg.test;
import com.llg.config.SpringDataJPAConfig;
import com.llg.pojo.Customer;
import com.llg.repositories.CustomeMethodNamerRepository;
import com.llg.repositories.CustomerRepositoryQueryByExample;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.List;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 18:20
*/
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class QueryByExample {
@Resource
CustomerRepositoryQueryByExample repository;
@Test
public void findAll(){
// 查询条件
Customer customer = new Customer();
customer.setCustName("李四");
customer.setCustAddress("1");
// 构建查询
Example<Customer> of = Example.of(customer);
List<Customer> customerByCustName = (List<Customer>) repository.findAll(of);
System.out.println("customerByCustName = " + customerByCustName);
}
@Test
public void findAll2(){
// 查询条件
Customer customer = new Customer();
customer.setCustName("四");
customer.setCustAddress("Jing");
// 创建条件匹配器
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnorePaths("custName") // 设置忽略的属性
.withIgnoreCase("custAddress") // 设置互联大小写
.withStringMatcher(ExampleMatcher.StringMatcher.ENDING) // 设置所有字符串匹配规则;
.withMatcher("custAddress",m -> m.endsWith()) ;//针对单个条件进行限制
// 构建查询
Example<Customer> example = Example.of(customer,matcher);
List<Customer> customerByCustName = (List<Customer>) repository.findAll(example);
System.out.println("customerByCustName = " + customerByCustName);
}
}
在之前使用Query by Example只能针对字符串进行条件设置,那如果希望对所有类型支持,可以使用Specifications
package com.llg.repositories;
import com.llg.pojo.Customer;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
import org.springframework.stereotype.Repository;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 16:48
*/
@Repository
public interface CustomerRepositorySpecifications extends PagingAndSortingRepository<Customer,Long>, JpaSpecificationExecutor<Customer>{
}
单元测试
package com.llg.test;
import com.llg.config.SpringDataJPAConfig;
import com.llg.pojo.Customer;
import com.llg.repositories.CustomerRepositoryQueryByExample;
import com.llg.repositories.CustomerRepositorySpecifications;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-23 18:20
*/
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Specification {
@Resource
CustomerRepositorySpecifications repository;
/**
* 地址 精确
*/
@Test
public void findAll(){
List<Customer> customerList = repository.findAll(new org.springframework.data.jpa.domain.Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
// root from Customer , 获取列
// CriteriaBuilder where 设置各种条件(>,<,in..)
// query 组合(order by,where)
Path<Object> custId = root.get("custId");
Path<Object> custName = root.get("custName");
Path<Object> custAddress = root.get("custAddress");
// 参数1 代表为哪个字段设置条件 参数2:值
Predicate predicate = criteriaBuilder.equal(custAddress, "BEIJING");
return predicate;
}
});
System.out.println("customerList = " + customerList);
}
/**
* 查询客户范围(in)
* id > 大于
* 地址 精确
*/
@Test
public void findAll2(){
List<Customer> customerList = repository.findAll((root, query, criteriaBuilder) -> {
// root from Customer , 获取列
// CriteriaBuilder where 设置各种条件(>,<,in..)
// query 组合(order by,where)
Path<Long> custId = root.get("custId");
Path<String> custName = root.get("custName");
Path<String> custAddress = root.get("custAddress");
// 参数1 代表为哪个字段设置条件 参数2:值
Predicate custAddressP = criteriaBuilder.equal(custAddress, "BEIJING");
Predicate custIdP = criteriaBuilder.greaterThan(custId, 2L);
CriteriaBuilder.In<String> in = criteriaBuilder.in(custName);
in.value("李四");
in.value("赵六");
Predicate predicate = criteriaBuilder.and(custAddressP, custIdP,in);
return predicate;
});
System.out.println("customerList = " + customerList);
}
/**
* 查询客户范围(in)
* id > 大于
* 地址 精确
*/
@Test
public void findAll3(){
Customer params = new Customer();
params.setCustAddress("beijing");
params.setCustId(1L);
params.setCustName("李四,赵六");
List<Customer> customerList = repository.findAll((root, query, criteriaBuilder) -> {
// root from Customer , 获取列
// CriteriaBuilder where 设置各种条件(>,<,in..)
// query 组合(order by,where)
Path<Long> custId = root.get("custId");
Path<String> custName = root.get("custName");
Path<String> custAddress = root.get("custAddress");
// 参数1 代表为哪个字段设置条件 参数2:值
List<Predicate> list = new ArrayList<>();
if (!StringUtils.isEmpty(params.getCustAddress())) {
list.add(criteriaBuilder.equal(custAddress, "BEIJING"));
}
if (params.getCustId() > -1) {
list.add(criteriaBuilder.greaterThan(custId, 2L));
}
if (!StringUtils.isEmpty(params.getCustName())) {
CriteriaBuilder.In<String> in = criteriaBuilder.in(custName);
in.value("李四");
in.value("赵六");
list.add(in);
}
Predicate predicate = criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
return predicate;
});
System.out.println("customerList = " + customerList);
}
/**
* 查询客户范围(in)
* id > 大于
* 地址 精确
*/
@Test
public void findAll4(){
Customer params = new Customer();
params.setCustAddress("beijing");
params.setCustId(1L);
params.setCustName("李四,赵六");
List<Customer> customerList = repository.findAll((root, query, criteriaBuilder) -> {
// root from Customer , 获取列
// CriteriaBuilder where 设置各种条件(>,<,in..)
// query 组合(order by,where)
Path<Long> custId = root.get("custId");
Path<String> custName = root.get("custName");
Path<String> custAddress = root.get("custAddress");
// 参数1 代表为哪个字段设置条件 参数2:值
List<Predicate> list = new ArrayList<>();
if (!StringUtils.isEmpty(params.getCustAddress())) {
list.add(criteriaBuilder.equal(custAddress, "BEIJING"));
}
if (params.getCustId() > -1) {
list.add(criteriaBuilder.greaterThan(custId, 2L));
}
if (!StringUtils.isEmpty(params.getCustName())) {
CriteriaBuilder.In<String> in = criteriaBuilder.in(custName);
in.value("李四");
in.value("赵六");
list.add(in);
}
Predicate predicate = criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
Order desc = criteriaBuilder.desc(custId);
return query.where(predicate).orderBy(desc).getRestriction();
});
System.out.println("customerList = " + customerList);
}
}
QueryDSL是基于ORM框架或SQL平台上的一个通用查询框架。借助QueryDSL可以在任何支持的ORM框架或SQL平台
上以通用API方式构建查询。
JPA是QueryDSL的主要集成技术,是JPQL和Criteria查询的代替方法。目前QueryDSL支持的平台包括
JPA,JDO,SQL,Mongodb 等等。
Querydsl扩展能让我们以链式方式代码编写查询方法。该扩展需要一个接口QueryDslPredicateExecutor,它定义了很
多查询方法。
接口继承了该接口,就可以使用该接口提供的各种方法了
引入依赖
<dependency>
<groupId>com.querydslgroupId>
<artifactId>querydsl-jpaartifactId>
<version>5.0.0version>
dependency>
<dependency>
<groupId>com.querydslgroupId>
<artifactId>querydsl-aptartifactId>
<version>5.0.0version>
<scope>providedscope>
dependency>
添加maven插件
这个插件是为了让程序自动生成query type(查询实体,命名方式为:“Q”+对应实体名)。
<build>
<plugins>
<plugin>
<groupId>com.mysema.mavengroupId>
<artifactId>apt-maven-pluginartifactId>
<version>1.1.3version>
<executions>
<execution>
<goals>
<goal>processgoal>
goals>
<configuration>
<outputDirectory>target/generated-sources/queriesoutputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessorprocessor>
configuration>
execution>
executions>
plugin>
plugins>
build>
执行mvn compile之后,可以找到该target/generated-sources/queries,然后IDEA标示为源代码目录即可.
QuerydslPredicateExecutor查询结果:
@Test
public void test01(){
QCustomer customer = QCustomer.customer;
//通过id查找
BooleanExpression eq = customer.custId.eq(2L);
Optional<Customer> one = repository.findOne(eq);
System.out.println("one = " + one);
}
/**
* 查询客户名称范围
* id 大于
* 地址 精确
*/
@Test
public void test02(){
QCustomer customer = QCustomer.customer;
// 客户名称范围
BooleanExpression and = customer.custName.in("李四", "王五", "赵六")
.and(customer.custId.gt(2L))
.and(customer.custAddress.eq("beijing"));
Iterable<Customer> all = repository.findAll(and);
System.out.println("all = " + all);
}
/**
* 查询客户名称范围
* id 大于
* 地址 精确
*/
@Test
public void test03(){
Customer params = new Customer();
// params.setCustId(2L);
params.setCustName("李四,王五,赵六");
params.setCustAddress("beijing");
QCustomer customer = QCustomer.customer;
// 初始条件,类似与1=1 永远成立
BooleanExpression expression = customer.isNotNull().or(customer.isNull());
expression = params.getCustId() !=null ? expression.and(customer.custId.gt(params.getCustId())) : expression;
expression = !StringUtils.isEmpty(params.getCustName())?expression.and(customer.custName.in(params.getCustName().split(","))):expression;
expression = !StringUtils.isEmpty(params.getCustAddress())?expression.and(customer.custAddress.eq(params.getCustAddress())):expression;
Iterable<Customer> all = repository.findAll(expression);
System.out.println("all = " + all);
}
自定义quaerydsl:
@PersistenceContext // 解决线程安全问题
EntityManager em;
/**
* 自定义列查询 、 分组
* 需要使用原生态的方式(Specification)
* 通过Repository进行查询,列、表都是固定
*/
@Test
public void test04(){
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
QCustomer customer = QCustomer.customer;
// 构建基于QUeryDSL的查询
JPAQuery<Tuple> tupleJPAQuery = queryFactory.select(customer.custId, customer.custName)
.from(customer)
.where(customer.custId.eq(1L))
.orderBy(customer.custId.desc());
// 执行查询
List<Tuple> fetch = tupleJPAQuery.fetch();
// 处理返回数据
for (Tuple tuple : fetch) {
System.out.println(tuple.get(customer.custId));
System.out.println(tuple.get(customer.custName));
}
}
/**
* 自定义列查询 、 分组
* 需要使用原生态的方式(Specification)
*/
@Test
public void test05(){
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
QCustomer customer = QCustomer.customer;
// 构建基于QUeryDSL的查询
JPAQuery<Long> longJPAQuery = queryFactory.select(customer.custId.sum())
.from(customer);
// .where(customer.custId.eq(1L))
// .orderBy(customer.custId.desc());
// 执行查询
List<Long> fetch = longJPAQuery.fetch();
// 处理返回数据
for (Long sum : fetch) {
System.out.println(sum);
}
}
JPA的@OneToOne注解中各个属性的默认值如下:
/**
cascade 设置关联操作
ALL, 所有持久化操作
PERSIST 只有插入才会执行关联操作
MERGE, 只有修改才会执行关联操作
REMOVE, 只有删除才会执行关联操作
fetch 设置是否懒加载
EAGER 立即加载(默认)
LAZY 懒加载( 直到用到对象才会进行查询,因为不是所有的关联对象 都需要用到)
orphanRemoval 关联移除(通常在修改的时候会用到)一旦把关联的数据设置null ,或者修改为其他的关联数据, 如果想删除关联数据, 就可以设置true
optional 限制关联的对象不能为null true 可以为null(默认 ) false 不能为null
mappedBy 将外键约束执行另一方维护(通常在双向关联关系中,会放弃一方的外键约束)
值= 另一方关联属性名
* */
以下是@JoinColumn注解的一些常用属性:
实现:
1.配置关联关系
@OneToOne
@JoinColumn(name=“外键字段名”)
@OneToOne
@JoinColumn(name = "account_id")
private Account account;
account
package com.llg.pojo;
import lombok.Data;
import javax.persistence.*;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-24 14:23
*/
@Data
@Entity
@Table(name = "tb_account")
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
}
2.配置关联操作:
/**
cascade 设置关联操作
ALL, 所有持久化操作
PERSIST 只有插入才会执行关联操作
MERGE, 只有修改才会执行关联操作
REMOVE, 只有删除才会执行关联操作
fetch 设置是否懒加载
EAGER 立即加载(默认)
LAZY 懒加载( 直到用到对象才会进行查询,因为不是所有的关联对象 都需要用到)
orphanRemoval 关联移除(通常在修改的时候会用到)一旦把关联的数据设置null ,或者修改为其他的关联数据, 如果想删除关联数据, 就可以设置true
optional 限制关联的对象不能为null true 可以为null(默认 ) false 不能为null
mappedBy 将外键约束执行另一方维护(通常在双向关联关系中,会放弃一方的外键约束)
值= 另一方关联属性名
* */
@OneToOne(cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval=true,
optional=false,
mappedBy = "customer")
@JoinColumn(name = "customer_id")
private Account account;
测试:
package com.llg;
import com.llg.config.SpringDataJPAConfig;
import com.llg.pojo.Account;
import com.llg.pojo.Customer;
import com.llg.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Optional;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-24 14:37
*/
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class OneToOneTest {
@Resource
private CustomerRepository repository;
@Test
public void testC(){
Account account = new Account();
account.setUsername("llg");
account.setPassword("123");
Customer customer = new Customer();
customer.setCustName("刘列广");
customer.setCustAddress("上海嘉定区");
customer.setAccount(account);
account.setCustomer(customer);
repository.save(customer);
}
@Test
public void testR(){
Optional<Customer> customer = repository.findById(2L);
System.out.println(customer.get());
}
@Test
// 为什么懒加载要配置事务
// 当通过repository调用查询方法,session就会立即关闭,一但session关闭你就不能查询,
// 加了事务后,就能让session直到事务执行完毕后才会关闭
@Transactional(readOnly = true)
public void testR_lazy(){
Optional<Customer> customer = repository.findById(2L);
System.out.println("=======================================");
System.out.println(customer.get());
}
@Test
public void testD(){
repository.deleteById(2L);
}
@Test
public void testU(){
Customer customer = new Customer();
customer.setCustName("刘列广");
customer.setCustId(3L);
customer.setCustAddress("上海嘉定区谢春路");
customer.setAccount(null);
repository.save(customer);
}
}
差异:-
这两个设置之间的区别在于对 断开关系.例如,当设置 地址字段设置为null或另一个Address对象.
如果指定了 orphanRemoval = true ,则会自动删除断开连接的Address实例.这对于清理很有用 没有一个不应该存
在的相关对象(例如地址) 来自所有者对象(例如员工)的引用.
如果仅指定 cascade = CascadeType.REMOVE ,则不会执行任何自动操作,因为断开关系不是删除操作
实现:
1.配置关联关系
@OneToMany
@JoinColumn(name=“customer_id”)
// 一对多
@OneToMany(cascade = CascadeType.ALL,orphanRemoval = true)
@JoinColumn(name="customer_id")
private List<Messsage> messsages;
2.配置关联操作
测试一对多
package com.llg;
import com.llg.config.SpringDataJPAConfig;
import com.llg.pojo.Account;
import com.llg.pojo.Customer;
import com.llg.pojo.Messsage;
import com.llg.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-24 14:37
*/
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class OneToManyTest {
@Resource
private CustomerRepository repository;
@Test
public void testC(){
Customer customer = new Customer();
customer.setCustName("刘列广");
customer.setCustAddress("上海嘉定区");
List<Messsage> messsageList = new ArrayList<>();
messsageList.add(new Messsage("你好"));
messsageList.add(new Messsage("在吗"));
customer.setMesssages(messsageList);
repository.save(customer);
}
@Test
@Transactional(readOnly = true)
public void testR(){
Optional<Customer> customer = repository.findById(1L);
System.out.println("===============================");
System.out.println("customer = " + customer);
}
}
测试多对一
package com.llg;
import com.llg.config.SpringDataJPAConfig;
import com.llg.pojo.Customer;
import com.llg.pojo.Messsage;
import com.llg.repositories.CustomerRepository;
import com.llg.repositories.MessageRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-24 14:37
*/
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ManyToOneTest {
@Resource
private MessageRepository repository;
@Test
public void testC(){
Customer customer = new Customer();
customer.setCustName("刘列广");
customer.setCustAddress("上海嘉定区");
List<Messsage> messsageList = new ArrayList<>();
messsageList.add(new Messsage("你好",customer));
messsageList.add(new Messsage("在吗",customer));
repository.saveAll(messsageList);
}
@Test
public void testR(){
Customer customer = new Customer();
customer.setCustId(1L);
customer.setCustName("llg");
List<Messsage> byCustomer = repository.findByCustomer(customer);
// 隐式调用toString方法
System.out.println("byCustomer = " + byCustomer);
}
}
1.配置管理关系
@ManyToMany
@JoinColumn(name=“customer_id”)
2.配置关联操作:
// 单向多对多
@ManyToMany(cascade = CascadeType.ALL)
/**
* 中间表需要通过@JoinTable维护外键
* name: 指定中间表的名称
* joinColumns 设置本表的外键名称
* inverseJoinColumns 设置关联表的外键名称
*/
@JoinTable(
name = "tb_customer_role",
joinColumns = {@JoinColumn(name = "c_id")},
inverseJoinColumns = {@JoinColumn(name = "r_id")}
)
private List<Role> roles;
3.测试
package com.llg;
import com.llg.config.SpringDataJPAConfig;
import com.llg.pojo.Customer;
import com.llg.pojo.Messsage;
import com.llg.pojo.Role;
import com.llg.repositories.CustomerRepository;
import com.llg.repositories.MessageRepository;
import com.llg.repositories.RoleRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.Commit;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @author llg
* @slogan 致敬大师,致敬未来的你
* @create 2024-09-24 14:37
*/
@ContextConfiguration(classes = SpringDataJPAConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ManyToManyTest {
@Resource
private CustomerRepository repository;
@Resource
private RoleRepository roleRepository;
@Test
public void testC(){
Customer customer = new Customer();
customer.setCustName("刘列广");
customer.setCustAddress("上海嘉定区");
List<Role> role = new ArrayList<>();
role.add(new Role("管理员"));
role.add(new Role("超级管理员"));
customer.setRoles(role);
repository.save(customer);
}
/**
* 保存,
* 1.如果希望保存的关联数据使用已有的,就需要从数据库中查出来(持久状态),否则 提示游离状态
* 2.如果一个业务方法有多个持久化操作,记得加上@Transactional,否则不能共用一个session
*/
@Test
@Transactional
@Commit
public void testC2(){
Customer customer = new Customer();
customer.setCustName("彭于晏");
customer.setCustAddress("上海嘉定区");
List<Role> role = new ArrayList<>();
role.add(roleRepository.findById(1L).get());
role.add(roleRepository.findById(2L).get());
role.add(new Role("超级管理员"));
customer.setRoles(role);
repository.save(customer);
}
@Test
@Transactional(readOnly = true)
public void testR(){
System.out.println(repository.findById(1L).get());
}
}
多对多其实不适合删除, 因为经常出现数据出现可能除了和当前这端关联还会关联另一端,此时删除就会: ConstraintViolationException。 要删除, 要保证没有额外其他另一端数据关联
hibernate
防止并发修改
private @Version Long version;
如何使用审计功能
首先申明实体类,需要在类上加上注解@EntityListeners(AuditingEntityListener.class),其次在application启动类中加上注解
EnableJpaAuditing,同时在需要的字段上加上@CreatedDate、@CreatedBy、@LastModifiedDate、@LastModifiedBy等注解。
这个时候,在jpa.save方法被调用的时候,时间字段会自动设置并插入数据库,但是CreatedBy和LastModifiedBy并没有赋值,因为需要实现AuditorAware接口来返回你需要插入的值
回你需要插入的值。
1.编写AuditorAware
// AuditorAware 返回当前用户
@Bean
public AuditorAware<String> auditorAware(){
return new AuditorAware() {
@Override
public Optional getCurrentAuditor() {
// 当前用户
return Optional.of("刘列广");
}
};
}
2.在实体类中声明@EntityListeners和相应的注解
@EntityListeners(AuditingEntityListener.class)
@CreatedBy
private String createdBy;
@LastModifiedBy
private String modifiedBy;
@CreatedDate
@Temporal(TemporalType.TIMESTAMP)
private Date dateCreated = new Date();
@LastModifiedDate
@Temporal(TemporalType.TIMESTAMP)
private Date dateModified = new Date();
3.在Application 中启用审计@EnableJpaAuditing
@EnableJpaAuditing
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring‐aspectsartifactId>
<version>5.3.10version>
<scope>testscope>
dependency>
经过测试如果你的实体类上面的多个字段使用了@CreatedBy这样的注解,只会有一个生效,也就是说在一次请求中,只会被调用一次
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>com.querydslgroupId>
<artifactId>querydsl-jpaartifactId>
<version>5.0.0version>
dependency>
<dependency>
<groupId>com.querydslgroupId>
<artifactId>querydsl-aptartifactId>
<version>5.0.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.30version>
dependency>
<dependency>
<groupId>io.swaggergroupId>
<artifactId>swagger-annotationsartifactId>
<version>1.5.21version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
如果集成queryDSL,需要在xml加入以下插件进行编译
com.mysema.maven
apt-maven-plugin
1.1.3
process
target/generated-sources/queries
com.querydsl.apt.jpa.JPAAnnotationProcessor
application配置文件:
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/article
username: root
password: root
jpa:
generate-ddl: true
show-sql: true
properties:
hibernate:
format_sql: true
持久层继承extends JpaRepository