郑州营销型网站建设哪家好,宝安中心区房价走势,玄武网站建设,南京网站设计制作公司排名简介 Spring Data为数据访问层提供了熟悉且一致的Spring编程模版#xff0c;对于每种持久性存储#xff0c;业务代码通常需要提供不同存储库提供对不同CURD持久化操作。Spring Data为这些持久性存储以及特定实现提供了通用的接口和模版。其目的是统一简化对不同类型持久性存储…简介 Spring Data为数据访问层提供了熟悉且一致的Spring编程模版对于每种持久性存储业务代码通常需要提供不同存储库提供对不同CURD持久化操作。Spring Data为这些持久性存储以及特定实现提供了通用的接口和模版。其目的是统一简化对不同类型持久性存储的访问。 JPA 全称为Java Persistence API(2019年重新命名为Jakarta Persistence API),是SUN官方提供一种ORM规范、O:Object R:Rlational M: Mapping 规范 1、ORM映射元素数据:JPA支持xml和注解两种元数据的形式元数据描述对象和表之间的映射关系框架据此实体对象持久化到数据表中如Enity、Table、Id与Column注解等 2、JPA的API用来操作实体对象执行CRUD操作框架在后台替我们完成所有事情开发者从繁琐的JDBC和SQL代码中解脱出来 3、JPQL查询语句:通过面向对象而非面向数据库的查询语句数据避免程序的SQL语句紧密耦合如from User where name ? Spring Data特性 1、模版制作Spring Data提供了对不同数据库对应的模版例如MongoTemplate、RedisTemplate、JDBCTemplate。模版提供存储特定CRUD操作Spring Data JPA不提供模版只是Spring Data JPA本身就是对JDBC API上的抽象。 2、对象/数据存储映射可以通过xml文件或注解来映射数据之间的关系 代码示例
Entity
Table(name User)
public class User {Idprivate String id;Column(name user_name)private String name;private Date lastLogin;OneToManyprivate ListRole roles;
}3、对Respository支持对持久层提供了基础的CRUD操作以及分页操作等 Hibernate入门案例
在项目目录下的resource创建一个hibernate.cfg.xml文件
?xml version1.0 encodingutf-8?
!DOCTYPE hibernate-configuration PUBLIC-//Hibernate/Hibernate Configuration DTD//ENhttp://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd
hibernate-configurationsession-factory!--配置数据库连接信息--property nameconnection.urljdbc:mysql://localhost:3306/spring_data_jpa/propertyproperty namehibernate.connection.usernameroot/propertyproperty namehibernate.connection.password123456/propertyproperty nameconnection.driver_classcom.mysql.jdbc.Driver/property!--选择数据库类型--property namehibernate.dialectorg.hibernate.dialect.MySQL5Dialect/property!--打印sql语句--property namehibernate.show_sqltrue/property!--格式化sql--property namehibernate.format_sqltrue/property!-- 表的生成策略自动生成默认不自动生成 --property namehbm2ddl.autoupdate/property!-- 映射实体类 --mapping classorg.example.entity.Customer//session-factory
/hibernate-configuration其中映射的实体类如下
Entity
Data
Table(name cst_customer)
public class Customer {/**** Id 声明主键配置* GeneratedValue 配置主键生成策略* Column 配置属性和字段映射关系* author Tang* date 2023/10/8 22:38:25*/IdGeneratedValue(strategy GenerationType.IDENTITY)Column(name cust_id)private Long custId;Column(name cust_name)private String custName;Column(name cust_address)private String custAddress;
}写入数据:
public class HibernateApp {public static void main(String[] args) {try (Session session initSessionFactory().openSession()) {Transaction tx session.beginTransaction();Customer customer new Customer();customer.setCustName(张三);session.save(customer);tx.commit();} catch (Exception e) {System.out.println(e);}}public static SessionFactory initSessionFactory() {return new MetadataSources(new StandardServiceRegistryBuilder().configure(/hibernate.cfg.xml).build()).buildMetadata().buildSessionFactory();}
}具体的CRUD操作详细见文档连接 文档
在项目跟目录下的resource创建META-INF目录并在其中创建persistence.xml文件其配置如下
?xml version1.0 encodingUTF-8?
persistence xmlnshttp://java.sun.com/xml/ns/persistence version2.0!-- jpa持久化单元 --persistence-unit namespringJpa transaction-typeRESOURCE_LOCAL!-- jpa实现方式 --providerorg.hibernate.ejb.HibernatePersistence/provider!-- 配置需要进行ORM的POJO类 --classorg.example.entity.Customer/classpropertiesproperty namejavax.persistence.jdbc.user valueroot/property namejavax.persistence.jdbc.password value123456/property namejavax.persistence.jdbc.driver valuecom.mysql.jdbc.Driver/property namejavax.persistence.jdbc.url valuejdbc:mysql://localhost:3306/spring_data_jpa/property namehibernate.show_sql valuetrue/property namehibernate.format_sql valuetrue/property namehibernate.hbm2ddl.auto valueupdate/property namehibernate.dialect valueorg.hibernate.dialect.MySQL5InnoDBDialect//properties/persistence-unit
/persistence
配置持久化单元并写入到数据库中 public static void main(String[] args) {EntityManager entityManager init().createEntityManager();EntityTransaction tx entityManager.getTransaction();tx.begin();// 持久化操作, 写入到mysql表中Customer customer new Customer();customer.setCustName(hello jpa);entityManager.persist(customer);tx.commit();}public static EntityManagerFactory init() {// 配置jpa持久化单元名称return Persistence.createEntityManagerFactory(springJpa);
}使用JPQL语句 JPQL代表Java持久化查询语言。它被用来创建针对实体的查询存储在关系数据库中。 JPQL是基于SQL语法的发展。但它不会直接影响到数据库。 JPQL可以检索使用SELECT子句中的数据可以使用 UPDATE子句做批量UPDATE和DELETE子句。 使用JPQL语句进行更新
public static void main(String[] args) {EntityManager entityManager init().createEntityManager();EntityTransaction tx entityManager.getTransaction();tx.begin();// 这里的Customer是映射的实体类名称其查询都是使用映射实体类的属性String jpql UPDATE Customer set custName:custName where custId:id;entityManager.createQuery(jpql).setParameter(custName, tang).setParameter(id, 3L).executeUpdate();tx.commit();
}也可以使用sql语句来进行对数据库的操作代码变更如下: String sql UPDATE cst_customer set cust_name:custName where cust_id:id;
entityManager.createNativeQuery(sql).setParameter(custName, tang).setParameter(id, 3L).executeUpdate();其中的cst_customer是表结构cust_name和cust_id是表的字段名 JPA对象四种状态 临时状态刚创建出来没有与entityManager发生关系没有被持久化不处于entityManager的对象中 持久状态与entityManager发生关系已经被持久化可以把持久化状态当做实实在在的数据库记录 删除状态执行remove方法事务提交之前 游离状态游离状态就是提交到数据库后事务commit后实体的状态因为事务已经提交了此时实体属性你如何改变都不会同步到数据库中。 persist方法可以将实例转换为managed状态在调用flush()方法或事务提交后实例将被插入到数据库中 Spring Data JPA入门 Spring Data JPA是Spring提供的一套简化JPA开发的框架按照约定好的规则进行方法命名来实现dao层接口就可以在不写接口实现的前提下实现对数据库的访问和操作。同时提供了很多除了CRUD在外的功能如分页、排序、复杂查询等功能 引入maven依赖
dependencies!-- 统一管理Spring Data子项目的版本 --dependencygroupIdorg.springframework.data/groupIdartifactIdspring-data-bom/artifactIdversion2021.1.0/versiontypepom/type/dependencydependencygroupIdorg.springframework.data/groupIdartifactIdspring-data-jpa/artifactIdversion2.7.7/version/dependencydependencygroupIdorg.hibernate/groupIdartifactIdhibernate-entitymanager/artifactIdversion5.6.15.Final/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.33/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.2.15/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-test/artifactIdversion5.1.10.RELEASE/versionscopetest/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.16.10/versionscopeprovided/scope/dependencydependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.12/version/dependency
/dependencies在resource文件夹下创建Spring.xml文件进行对JPA的配置
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:jpahttp://www.springframework.org/schema/data/jpa xmlns:txhttp://www.springframework.org/schema/txxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/data/jpahttps://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd!-- 整合jpa 配置entityManagerFactory以及对应的事务 --jpa:repositories base-packageorg.example.repositoriesentity-manager-factory-refentityManagerFactorytransaction-manager-reftransactionManager/!-- 配置EntityManagerFactory的Bean --bean nameentityManagerFactory classorg.springframework.orm.jpa.LocalContainerEntityManagerFactoryBeanproperty namejpaVendorAdapterbean classorg.springframework.orm.jpa.vendor.HibernateJpaVendorAdapterproperty namegenerateDdl valuetrue/property nameshowSql valuetrue//bean/propertyproperty namepackagesToScan valueorg.example.entity/property namedataSource refdataSource//bean!-- 配置数据源 --bean classcom.alibaba.druid.pool.DruidDataSource namedataSourceproperty nameurl valuejdbc:mysql://localhost:3306/spring_data_jpa/property namedriverClassName valuecom.mysql.jdbc.Driver/property nameusername valueroot/property namepassword value123456//bean!-- 配置说明式事务 --bean classorg.springframework.orm.jpa.JpaTransactionManager nametransactionManagerproperty nameentityManagerFactory refentityManagerFactory//bean!-- 配置注解式事务 --tx:annotation-driven transaction-managertransactionManager/
/beans
其中Spring.xml文件的配置可以等同于如下配置类
Configuration
EnableJpaRepositories(basePackages org.example.repositories)
EnableTransactionManagement
public class SpringDataJpaConfig {Beanpublic DataSource dataSource() {DruidDataSource druidDataSource new DruidDataSource();druidDataSource.setUsername(root);druidDataSource.setPassword(123456);druidDataSource.setDriverClassName(com.mysql.jdbc.Driver);druidDataSource.setUrl(jdbc:mysql://localhost:3306/spring_data_jpa);return druidDataSource;}Beanpublic LocalContainerEntityManagerFactoryBean entityManagerFactory() {HibernateJpaVendorAdapter vendorAdapter new HibernateJpaVendorAdapter();vendorAdapter.setGenerateDdl(true);LocalContainerEntityManagerFactoryBean factory new LocalContainerEntityManagerFactoryBean();factory.setJpaVendorAdapter(vendorAdapter);factory.setPackagesToScan(org.example.entity);factory.setDataSource(dataSource());return factory;}Beanpublic PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {JpaTransactionManager txManager new JpaTransactionManager();txManager.setEntityManagerFactory(entityManagerFactory);return txManager;}
}
Spring data jpa 增删改查
// 使用配置类直接变更为ContextConfiguration(classes SpringDataJpaConfig.class)
ContextConfiguration(locations /Spring.xml)
RunWith(SpringJUnit4ClassRunner.class)
public class SpringDataJPATest {AutowiredCustomerRepositories customerRepositories;Testpublic void testQuery() {OptionalCustomer customer customerRepositories.findById(1L);customer.ifPresent(System.out::println);}Testpublic void testInsert() {Customer customer new Customer();customer.setName(hello jpa test);customerRepositories.save(customer);}Testpublic void testUpdate() {Customer customer new Customer();customer.setId(3L);customer.setName(hello jpa test update);customerRepositories.save(customer);}Testpublic void testDelete() {Customer customer new Customer();customer.setId(3L);customerRepositories.delete(customer);}
}
Spring Data Repositories Spring Data Respositories的抽象目的是为了减少各种持久层存储实现数据访问层所需的样板代码。其中CrudRepository提供了简单的增删改查的操作。PagingAndSortingRepository在增删改查的基础上添加了分页排序的操作。 PagingAndSortingRepository演示代码
Autowired
CustomerRepositories customerRepositories;
Test
public void testPaging() {PageCustomer all customerRepositories.findAll(PageRequest.of(0, 2));System.out.println(all.getContent());
}
Test
public void testSort() {// 通过对实体类的id属性进行降序排列IterableCustomer sorted customerRepositories.findAll(Sort.sort(Customer.class).by(Customer::getId).descending());System.out.println(sorted);
}如果需要多个字段进行排序代码变更如下
IterableCustomer sorted customerRepositories.findAll(Sort.sort(Customer.class).by(Customer::getId).descending().and(Sort.sort(Customer.class).by(Customer::getName)));JPQL和SQL Spring Data JPA提供了多种自定义操作比如使用JPQL或者原始的SQL、规定的方法名称、Query by Examply、通过Specifications、通过Querydsl方式 使用JPQL进行查询 JPQL语法格式详细见 JPQL语法文档 在Repositories进行改造
public interface CustomerRepositories extends PagingAndSortingRepositoryCustomer, Long {Query(FROM Customer where name?1)Customer findCustomerByName(String name);
}也可以通过具名参数来进行JPQL语句的条件查询
public interface CustomerRepositories extends PagingAndSortingRepositoryCustomer, Long {Query(FROM Customer where name:customerName)Customer findCustomerByName(Param(customerName) String name);
}执行增删改操作 在Spring Data JPA中对增删改都需要加上事务,同时添加Modifying注解通知Spring Data JPA执行增删改操作 public interface CustomerRepositories extends PagingAndSortingRepositoryCustomer, Long {TransactionalModifyingQuery(UPDATE Customer c set c.name:custName where c.id:id)int updateCustomer(Param(custName) String custName, Param(id) Long id);
}其中c.name和c.id都是实体类的属性名如果是新增一定只能是在Hibernate下才能支持而且必须是INSERT INTO SELECT的方式来进行插入其他方法不支持新增方法 使用原生SQL
public interface CustomerRepositories extends PagingAndSortingRepositoryCustomer, Long {Query(value SELECT * FROM cst_customer where cust_name:custName, nativeQuery true)ListCustomer findCustomerByName(Param(custName) String name);
}其中cst_customer是数据库表名,cust_name是数据库表字段当使用原生SQL时需要在Query注解的nativeQuery设置为true 指定方法规则名称
支持查询的主题关键字前缀 决定方法的作用、只支持查询和删除的操作 关键字描述find...By、read..By、get...By、query...By、search..By、stream..By通用查询方法通常返回存储库类型、Collection或Streamable子类型或结果包装类例如PageGeoResults或任何其他特定与商店的结果包装类。可以作findBy..、findMyDomainTypeBy...或与其他关键字结合使用exists..By存在投影。通常返回boolean结果count..By计数投影返回数字结果delete...By、remove...By删除查询方法返回无结果void或者删除计数..Firstnumber...、...Topnumber..将查询结果限制为第一个number结果。此关键字可以出现主题的find和其他关键字和之间的任何位置By...Distinct...使用不同查询仅返回唯一结果。查阅特定与商店的问题是否支持该功能。此关键字可以出现在主题find和其他关键字和之间任何位置By
支持查询方法谓词关键字和修饰符 决定查询条件 关键词样本JPQL片段DistinctfindDistinctByLastnameAndFirstnameselect distinct .. where x.lastname ?1 and x.firstname ?2AndfindByLastnameAndFirstname.. where x.lastname ?1 and x.firstname ?2OrfindByLastnameOrFirstname..where x.lastname ?1 and x.firstname ?2Is、EqualsfindByFirstname、findByFirstnameIs、findByFirstnameEquals..where x.firstname ?1BetweenfindByStartDateBetween...where x.startDate between ?1 and ?2LessThanfindByAgeLessThan...where x.age ?1LessThanEqualfindByAgeLessThanEqual..where x.age ?1GreaterThanfindByAgeGreaterThan..where x.age ?1GreaterThanEqualfindByAgeGreaterThanEqual..where x.age ?1AfterfindByStarterDateAfter..where x.startDate ?1BeforefindByStartDateBefore..where x.startDate ?1IsNull、NullfindByAge(Is)Null..where x.age is nullIsNotNull、NotNullfindByAge(Is)NotNull..where x.age not nullLikefindByFirstnameLike..where x.firstname like ?1 自己指定%位置NotLikefindByFirstnameNotLike..where x.firstname not like ?1自己指定%位置StartingWithfindByFirstnameStartingWith..where x.firstname like ?2参数绑定了append%EndingWithfindByFirstnameEndingWith..where x.firstname like ?1(参数绑定了prepended%)ContainingfindByFirstnameContaining..where x.firstname like ?1(参数绑定包裹在%)OrderByfindByAgeOrderByLastnameDesc..where x.age ?1 order by x.lastname descNotfindByLastnameNot..where x.lastname ?1InfindByAgeIn(CollectionAge ages)..where x.age in ?1NotInfindByAgeNotIn(CollectionAge ages)..where x.age not in ?1TruefindByActiveTrue()..where x.active trueFalsefindByActiveFalse()..where x.active falseIgoreCasefindByFirstnameIgoreCase..where UPPER(x.firstname) UPPER(?1)
详细查阅官方文档官方文档
代码示例
public interface CustomerMethodNameRepositories extends PagingAndSortingRepositoryCustomer, Long {ListCustomer findByName(String name);
}其中的name是实体类中Customer类中的name属性 删除操作
public interface CustomerMethodNameRepositories extends PagingAndSortingRepositoryCustomer, Long {TransientModifyingvoid deleteById(Long id);
}需要使用Transient开启事务以及使用Modifying告诉Spring Data JPA这是增删改操作 模糊查询
public interface CustomerMethodNameRepositories extends PagingAndSortingRepositoryCustomer, Long {ListCustomer findByNameLike(String name);
}调用方法是需要指定%如下 ContextConfiguration(classes SpringDataJpaConfig.class)
RunWith(SpringJUnit4ClassRunner.class)
public class MethodNameTest {Autowiredprivate CustomerMethodNameRepositories customerMethodNameRepositories;Testpublic void queryLikeTest() {ListCustomer customers customerMethodNameRepositories.findByNameLike(%test%);System.out.println(customers);}
}动态条件查询
Query By Example 只支持查询,不支持嵌套或者分组的属性约束如firstname?0或者firstname?1 and lastname?2只支持字符串 start/contains/ends/regex匹配和其他属性类型精确匹配。 详细查询官方文档 使用Ctrl F 搜索by example
查询所有
public interface QueryByExampleRepositories extends PagingAndSortingRepositoryCustomer, Long,QueryByExampleExecutorCustomer {
}接口需要继承QueryByExampleExecutor同时查询时需要通过Example.of()构建查询条件 Test
public void queryTest() {// 查询条件通过Example.of()构建查询条件Customer customer new Customer();customer.setName(test);IterableCustomer all queryByExampleRepositories.findAll(Example.of(customer));System.out.println(all);
}构建条件匹配器
Test
public void queryWhereRegexTest() {Customer customer new Customer();customer.setName(张三);customer.setAddress(shanghai);// 忽略指定的属性IterableCustomer ignore queryByExampleRepositories.findAll(Example.of(customer, ExampleMatcher .matching().withIgnorePaths(address)));System.out.println(ignore);
}其中address是实体类Customer类中的属性 Specifications查询方式 Query By Example的查询方式只支持字符串且无法对查询条件做出、和的限制所以需要使用Specifications的查询方式来实现但Specifications的查询方式不能使用分组、聚合函数。 public interface SpecificationsRepositories extends CrudRepositoryCustomer, Long,JpaSpecificationExecutorCustomer {
}使用Specifications的查询方式需要继承JpaSpecificationExecutor接口如下案例查询address是BEIJIN且id在3,20,18的数据 Test
public void queryTest() {IterableCustomer all specificationsRepositories.findAll((SpecificationCustomer)(root, query, criteriaBuilder) - criteriaBuilder .and(criteriaBuilder.equal(root.get(id), BEIJIN), criteriaBuilder.in(root.get(address)).value(3L).value(20L).value(18L)));all.forEach(System.out::println);
}参数说明 (root, query, criteriaBuilder)中的root相当于from Customer可以获取查询的列,criteriaBuilder设置各种查询条件如、或者in等操作、query设置各种组合条件如order by、where等。 QueryDSL QueryDSL是基于ORM框架或者SQL平台上的一个通用查询框架借助QueryDSL可以在任何支持的ORM框架或者SQL平台上以通用的API方式构建查询。 引入依赖
dependencygroupIdcom.querydsl/groupIdartifactIdquerydsl-jpa/artifactIdversion4.4.0/version
/dependency安装插件
buildpluginsplugingroupIdcom.mysema.maven/groupIdartifactIdapt-maven-plugin/artifactIdversion1.1.3/versiondependenciesdependencygroupIdcom.querydsl/groupIdartifactIdquerydsl-apt/artifactIdversion4.4.0/version/dependency/dependenciesexecutionsexecutionphasegenerate-sources/phasegoalsgoalprocess/goal/goalsconfigurationoutputDirectorytarget/generated-sources/queris/outputDirectoryprocessorcom.querydsl.apt.jpa.JPAAnnotationProcessor/processorlogOnlyOnErrortrue/logOnlyOnError/configuration/execution/executions/plugin/plugins
/build导入依赖并安装好插件后使用maven compile一下 将编译生成的QClass进行source 这样子就可以引用编译生成的QClass 查询案例
public interface QueryDSLRepositories extends QuerydslPredicateExecutorCustomer, CrudRepositoryCustomer, Long {
}注意必须继承QuerydslPredicateExecutor和CrudRepository或CrudRepository的子类 ContextConfiguration(classes SpringDataJpaConfig.class)
RunWith(SpringJUnit4ClassRunner.class)
public class QueryDSLTest {Autowiredprivate QueryDSLRepositories queryDSLRepositories;Testpublic void queryTest() {QCustomer customer QCustomer.customer;IterableCustomer all queryDSLRepositories.findAll(customer.id.in(1L, 18L, 20L).and(customer.id.gt(5L)).and(customer.address.eq(BEIJIN)));all.forEach(System.out::println);}
}相当于sql语句SELECT * FROM customer WHERE id IN(1, 18, 20) AND id 5 AND address BEIJIN 自定义列查询或者分组查询
ContextConfiguration(classes SpringDataJpaConfig.class)
RunWith(SpringJUnit4ClassRunner.class)
public class QueryDSLTest {PersistenceContext // 保证线程安全private EntityManager entityManager;Testpublic void groupQueryTest() {JPAQueryFactory factory new JPAQueryFactory(entityManager);QCustomer customer QCustomer.customer;JPAQueryTuple query factory.select(customer.id, customer.name).from(customer).where(customer.id.eq(18L)).orderBy(customer.id.desc());ListTuple fetch query.fetch();for (Tuple tuple : fetch) {System.out.println(tuple.get(customer.id));System.out.println(tuple.get(customer.name));}}
}相当于SQL语句SELECT id, name FROM customer WHERE id 18 ORDER BY id DESC 多表关联
一对一 配置关联关系实体类Customer配置单向关联 Data
Entity
Table(name cst_customer)
public class Customer {IdGeneratedValue(strategy GenerationType.IDENTITY)Column(name cust_id)private Long id;Column(name cust_address)private String address;Column(name cust_name)private String name;// 单向关联OneToOne(cascade CascadeType.PERSIST)JoinColumn(name account_id)private Account account;
}注解OneToOne的cascade参数说明: CascadeType.PERSIST 级联持久化保存操作持久保存拥有方实体时也会持久保存该实体的所有相关数据。这个属性就是造成上面问题的关键。当你保存一天条数据时所有的关联数据都会进行保存无论数据库里面有没有但有时候我们是需要这样的级联操作的。 CascadeType.REMOVE 级联删除操作删除当前实体时与它有映射关系的实体也会跟着被删除。 CascadeType.DETACH 级联脱管/游离操作如果你要删除一个实体但是它有外键无法删除你就需要这个级联权限了。它会撤销所有相关的外键关联。 CascadeType.REFRESH 级联刷新操作假设场景 有一个订单,订单里面关联了许多商品,这个订单可以被很多人操作,那么这个时候A对此订单和关联的商品进行了修改,与此同时,B也进行了相同的操作,但是B先一步比A保存了数据,那么当A保存数据的时候,就需要先刷新订单信息及关联的商品信息后,再将订单及商品保存。 CascadeType.MERGE 级联更新合并操作当Student中的数据改变会相应地更新Course中的数据。 CascadeType.ALL 清晰明确拥有以上所有级联操作权限。 fetch参数说明: fetch参数的作用类似于设计模式中的单例模式默认为EAGER饿汉模式,可以设置为LAZY懒汉模式当设置为LAZY的时候只有在使用到对应的实体类的时候就会加载执行查询 示例在Customer类中对应的属性添加如下代码 OneToOne(cascade CascadeType.PERSIST,fetch FetchType.LAZY)
JoinColumn(name account_id)
private Account account;查询案例
Test
Transactional(readOnly true)
public void queryTest() {OptionalCustomer byId repositories.findById(1L);System.out.println(byId.get());
}需要添加Transactional注解开启事务这是由于通过repositories接口来调用查询方法执行完后session会立即关闭一旦session关闭了就不能进行查询了所以在fetch FetchType.LAZY的情况下执行完repositories.findById(1L)后会关闭session导致在执行byId.get()调用查询会报错。而事务是在整个方法执行完后关闭session 实体类Account配置如下 Data
Entity
Table(name cst_account)
public class Account {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long id;private String username;private String password;
}测试代码
public interface CustomerRepositories extends PagingAndSortingRepositoryCustomer, Long {
}ContextConfiguration(classes SpringDataJpaConfig.class)
RunWith(SpringJUnit4ClassRunner.class)
public class OneToOneTest {Autowiredprivate CustomerRepositories repositories;Testpublic void saveTest() {Account account new Account();account.setUsername(xushu);Customer customer new Customer();customer.setName(徐庶);customer.setAccount(account);repositories.save(customer);}
}如果出现Field id doesnt have a default value的错误请检查对应的表的主键Id是否设置为自增 一对多 表设计如下 实体类Message配置如下: Data
Entity
Table(name cst_message)
public class Message {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long id;private String info;public Message(String info) {this.info info;}public Message() {}
}必须需要拥有无参构造函数 实体类Customer配置如下: Data
Entity
Table(name cst_customer)
public class Customer {IdGeneratedValue(strategy GenerationType.IDENTITY)Column(name cust_id)private Long id;Column(name cust_address)private String address;Column(name cust_name)private String name;OneToMany(cascade CascadeType.ALL)JoinColumn(name customer_id)private ListMessage messages;
}注意当查询一对多的数据表的时候Spring Data JPA默认使用的是懒加载所以需要使用Transactional开启事务来解决运行时出现no-session的错误 示例代码
Test
Transactional
public void testQuery() {OptionalCustomer byId repositories.findById(7L);System.out.println(byId.get());
}或者在实体类中的Customer中添加OneToMany(cascade CascadeType.ALL, fetch FetchType.EAGER)注解解决出现no-session错误如下: OneToMany(cascade CascadeType.ALL, fetch FetchType.EAGER)
JoinColumn(name customer_id)
private ListMessage messages;一对多删除操作注意事项 如果在Customer实体类中OneToMany的cascade CascadeType.PERSIST这会只删除Customer表中的信息不会删除Message表中的信息 多对一
实例代码: Message实体类中进行绑定 Data
Entity
Table(name cst_message)
public class Message {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long id;private String info;ManyToOne(cascade CascadeType.PERSIST)JoinColumn(name customer_id)private Customer customer;public Message(String info) {this.info info;}public Message(Customer customer, String info) {this.customer customer;this.info info;}public Message() {}
}使用注解ManyToOne(cascade CascadeType.PERSIST)以及JoinColumn(name customer_id) 多对多 多对多表的关系如下: 注意:在cst_customer_role表中不需要任何主键 Customer类配置如下:
Data
Entity
Table(name cst_customer)
public class Customer {IdGeneratedValue(strategy GenerationType.IDENTITY)Column(name cust_id)private Long id;Column(name cust_address)private String address;Column(name cust_name)private String name;OneToMany(cascade CascadeType.PERSIST, fetch FetchType.LAZY)JoinColumn(name customer_id)private ListMessage messages;public Customer(String name) {this.name name;}public Customer() {}/*** 单向的多对多* 中间表需要通过JoinTable来维护外键* name 指定中间表名称* joinColumn 设置本表的外键名称* inverseJoinColumns 关联表的外键名称*/ManyToMany(cascade CascadeType.PERSIST)JoinTable(name cst_customer_role,joinColumns {JoinColumn(name cust_id)},inverseJoinColumns {JoinColumn(name role_id)})private ListRole roles;Overridepublic String toString() {return Customer{ id id , address address \ , name name \ };}
}Role类信息如下:
Data
Entity
Table(name cst_role)
public class Role {IdGeneratedValue(strategy GenerationType.IDENTITY)Column(name role_id)private Long id;Column(name role_name)private String name;public Role(String name) {this.name name;}public Role() {}
}实例代码
/***
* 如果保存的关联对象的数据希望使用数据库已有的数据
* 那么就需要从数据库中查询出来。否则会抛出异常
* 同事需要使用Transactional来解决报错问题
* 单元测试需要使用Commit解决事务持久化问题
* return void
* author Tang
* date 2023/12/6 23:25:17
*/
Test
public void testSave() {Customer customer new Customer();customer.setName(zhangshang);ListRole roles new ArrayListRole() {{add(new Role(超级管理员));add(new Role(商品管理员));}};customer.setRoles(roles);customerRepository.save(customer);
}其中如果出现了Field xxx_id doesnt have a default value,是在数据库方没有设置主键自增所导致的 审计 为了数据库中的数据方便溯源所以经常需要在数据库中添加创建人、修改人、修改时间、创建时间。由于经常频繁的操作所以Spring data jpa使用审计功能来解决这个问题操作如下 由于Spring Data JPA的审计功能需要依赖Spring AOP相关依赖否则会抛出Could not configure Spring Data JPA auditing-feature because spring-aspects.jar is not on the classpath!异常
dependencygroupIdorg.springframework/groupIdartifactIdspring-aspects/artifactIdversion5.3.28/version
/dependency在对应的实体类添加如下字段 // 创建人CreatedByprivate String creator;// 修改人LastModifiedByprivate String modifier;// 创建时间 Temporal 注解指定时间类型Temporal(TemporalType.TIMESTAMP)CreatedDateprivate Date dateCreated new Date();// 修改时间Temporal(TemporalType.TIMESTAMP)LastModifiedDateprivate Date dateModified new Date();同时在实体类上添加EntityListeners(AuditingEntityListener.class)用于监听审计监听对应的实体类 在配置类上配置如下Bean信息
/***
* 配置审计功能AuditorAware中泛型的类型与
* 后端获取到的用户类型一直可以是String可以是User对象等
* return org.springframework.data.domain.AuditorAwarejava.lang.String
* author Tang
* date 2023/12/7 23:19:17
*/
Bean
public AuditorAwareString auditorAware() {return () - Optional.of(创建人);
}使用EnableJpaAuditing开启审计功能