Spring data jpa的使用说明

    技术2025-01-21  17

    1.什么是spring data jpa?

    是一种基于jpa进行的再次封装的框架,其底层原理还是由其他框架实现的(这里用的是hibernate)

    2.配置的过程

    (1)创建一个maven工程,在pom文件中导入相应的坐标。

    单元测试 junit 4.9 Aspectjweaver 支持切入点表达式和aop相关注解 Spring相关 版本都是4.2.4.RELEASE Spring-aop aop切面编程的支持包 Spring-test 单元测试和集成测试的简单封装 Spring-context Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等 Spring-context-support 拓展支持,用于MVC方面 Spring-beans spring ioc的基础实现 Spring-core spring核心组件 Spring-orm 整合第三方的orm框架 Hibernate相关 版本 5.0.7.Final Hibernate-core hibernate核心包 Hibernate-entitymanager 实体管理包(和jpa整合) Hibernate-validator 参数校验 C3p0 0.9.1.2 连接池 Log4j 1.2.12 日志 Slf4j-log4j12 1.6.6 Mysql-connector-java 5.1.6 数据库 Spring-data-jpa 1.9.0.RELEASE spring-data-jpa 核心包 Javax.el-api 2.2.4 必须导入的包 Javax.el 2.2.4

    (2)在applicationContext中编写对应的配置文件。

    1.配置数据源

    <context:property-placeholder location="classpath:jdbc.properties"/><!-- 定义引用的文件,这样写容易改动--> <context:component-scan base-package="com.cn"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- c3p0数据源--> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="driverClass" value="${jdbc.driver}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean>

    2.配置实体管理工厂bean

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> //配置数据源 <property name="dataSource" ref="dataSource"/> //指定扫描实体类的包 <property name="packagesToScan" value="com.cn.entity"/> //配置持续化提供者 <property name="persistenceProvider"> //使用的是hibernate <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/> //配置jpa适配器 </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"/> //是否显示sql语句 <property name="showSql" value="true"/> </bean> </property> <property name="jpaProperties"> <props> //配置在更新时,是否创建表,创建表是否删除之前表的内容 <prop key="hibernate.hbm2dd1.auto">update</prop> </props> </property> </bean>

    3.配置事务和jpa的相关配置。

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> //jpa:repositories jpa仓库 需要指定dao放置的位置 base-package <jpa:repositories base-package="com.cn.dao" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"/>

    (3)创建实体类

    将注解映射到数据库表中,配置和jpa配置相同

    (4)编写实体类的dao接口

    需要继承两个接口JpaRepository<T,ID>和JpaSpecificationExecutor T 代表实体类 ID代表 实体类的主键

    public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer>

    1.JpaRepository<T,ID>提供了一些简单的数据库操作方法 FindOne 通过主键查询单个 Sava 保存,如果有主键就更新,没有就添加 Delete 通过主键删除 FindAll 查询所有 2.复杂的操作有多种方式进行查询

    JPQL查询(查询需要加上Query注解,修改还需要加上Modifying注解) //查询 @Query(value = "from Customer where custName= ? ") Customer findByName(String name); //更新,1代表第一个参数,2代表第二个参数,表示方法定义的时候两个参数的顺序 @Query(value = "update Customer set custName=?1 where custId=?2") @Modifying void update(String custName,long custId);

    调用更新方法的时候,因为需要对数据库内容进行修改,所以需要配置事务注解 @Transactional @Rollback(value = false)

    使用sql语句 //查询 @Query(value = "select * from cst_customer",nativeQuery = true) public List<Customer> findBySql(); //更新 @Query(value = "update cst_customer set cust_name=? where cust_id=?",nativeQuery = true) @Modifying void updatesql(String custName,long custId);

    使用sql语句,只需要在@Query注解上面加上nativeQuery = true就可以了,其余和jsql的方式一样

    3.使用方法查询,由jpa内部自动生成sql语句进行创建

    方法查询的规范 find+全局修饰+By+实体属性名称+限定词+连接词+(其他实体属性)+OrderBy+排序属性+排序方向 如:findDistinctByFirstNameIgnoreCaseAndLastNameOrderByAgeDesc(String firstName,String lastName) 4.使用Spring data jpa 中JpaSpecificationExecutor接口 我们要使用其中的方法就必须了解Specification接口 它定义了一个方法toPredicate 其中 有三个参数Root (代表想要查询表的实体类) CriteriaQuery 顶层查询 CriteriaBuilder 具体查询标准 ①相关查询 精确查询: cb.equla(root.get(“custName”),”哈哈”); 并列查询: cb.equla(root.get(“custName”),”哈哈”); cb.equla(root.get(“custId”),”1”); cb.and(p1,p2); 模糊查询: cb.like(root.get(“custName”).as(String.class),”哈%”); 排序查询: 排序查询只需要创建一个排序对象 Sort sort=new Sort(Sort.Direction.DESC,”custName”);第一个参数代表排序方式,第二个表示通过哪个属性排序 分页查询: 分页查询需要一个Pageable对象这个 声明该对象 Pageable pageable=new PageRequest(0,3) 第一个参数从哪开始 第二个参数 一页有几个数据 然后通过customerDao接口调用方法 返回一个分页对象 这个对象是spring data jpa 所提供的 里面包含分页需要的所有属性 totalElements获总数据数量 totalPages 获得一页有几个数据 content 表示 返回的内容

    //一般查询 Specification<Customer> spec=new Specification<Customer>(){ public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) { //root就是 相当于实体类对象 query 自定义查询 cb:构建查询 return cb.like(root.get("custName").as(String.class),"7%"); } }; List<Customer> all = customerDao.findAll(spec); //排序查询 customerDao.findAll(new Sort(Sort.Direction.DESC,"custName") //分页查询 Pageable pageable=new PageRequest(0,3); Page<Customer> customers = customerDao.findAll(pageable); System.out.println(customers.getTotalElements()); System.out.println(customers.getTotalPages()); System.out.println(customers.getContent());

    3.关于一对多和多对多的操作

    (1)一对多

    一的一方:

    /* @OneToMany(targetEntity = LinkMan.class) @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")*/ @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL) private Set<LinkMan> linkmans=new HashSet<LinkMan>();

    多的一方:

    @ManyToOne(targetEntity = Customer.class,fetch =FetchType.LAZY ) @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") private Customer customer;

    ① 主要区别在于 在实体类中 要和 其他类有关系

    操作在于 1的一方需要有一个存储多的一方的集合,并且需要加上注释@OneToMany(mappedBy=”customer”,cascade=Cascade.Type.ALL) 其中mappedBy 表示放弃维护权,第二个代表级联操作:操作一个对象同时操作它的关联对象 为何要放弃维护权? 因为多对一方再保存的时候已经保存了外键信息,所以不需要再进行更新了 多的一方需要添加一个一的一方的对象同时需要加上注释 @ManyToOne(targetEntity=Customer.class,fetch=FetchType.LAZY) @JoinColumn(name=”lkm_cust_id”,referencedColumnName=”cust_id”) 第一个代表多对一,属性为 目标实体类 需要一方面的字节码文件,还可以配置加载方式 LAZY为懒加载,EAGER为直接加载 第二个注释中 名字为 外键名,第二个为该外键在主表的名字

    ② 多表操作(1对多)增删改查

    Add:需要加上@Transaction和@Rollback(注释) 添加的时候 因为使用级联操作,所以只需要在主方进行保存(一方) Delete:删除的时候,一方删除就可以了 Update:无特殊 Search:查询的时候通过对象导航进行查询,但是再toString方法中一定要删除其中一个的输出另一个类的方法,不然会无限循环,出错 同时查询要加上@Transactional注释

    (2)多对多

    双方:

    //role方 @ManyToMany(targetEntity = User.class,cascade = CascadeType.ALL) @JoinTable(name = "role_user",joinColumns = { @JoinColumn(name = "ru_role_id",referencedColumnName = "role_id") },inverseJoinColumns = { @JoinColumn(name = "ru_user_id",referencedColumnName = "user_id") }) private Set<User> users=new HashSet<User>(); --------------------------------------------- //user方 @ManyToMany(mappedBy = "users") private Set<Role> roles=new HashSet<Role>();

    ①配置相关说明

    建议多对多的时候也是 一个负责 维护 一个放弃 需要在两个类中各加入一个对方的集合 在集合上面进行配置

    主 类 @ManyToMany(targetEntity=User.class,cascade=CascadeType.ALL) @JoinTable(name=”role_user”,joinColumns={ @JoinColumn(name=”ru_role_id,referencedColumnName=”role_id”) },inverseJoinColumns={@JoinColumn(name=”ru_user_id”,referencedColumnName=”user_id”)} ) 其中JoinTable为中间表 joinColumns 中 name为中间表中的主外键名 referencedColumnName为 主表中名 inverseJoinColumns中第一个为中间表中另一个表的外键名 referencedColumnName为 另一个表中的主表外键名

    第二个类只需要在集合方法上加上@ManyToMany(mappedBy=”users”)

    ② 多表操作增删改查

    增加:主类操作 删除:主类进行删除(会删除所有相关) 修改:各改各的 查:互相的都可以查,但是toString中 要删除一个 否则会报错 一方查多方:默认延迟加载,因为多方数据多 多方查一方:默认即时加载,因为一方数据只有一条

    Processed: 0.009, SQL: 9