前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring 全家桶之 Spring Data JPA(四)

Spring 全家桶之 Spring Data JPA(四)

作者头像
RiemannHypothesis
发布2022-08-19 15:31:16
1.6K0
发布2022-08-19 15:31:16
举报
文章被收录于专栏:Elixir

一、多表查询之一对多

一对多

新建maven项目one2many

导入maven依赖

代码语言:javascript
复制
<properties>
    <spring.version>5.0.2.RELEASE</spring.version>
    <hibernate.version>5.0.7.Final</hibernate.version>
    <slf4j.version>1.6.6</slf4j.version>
    <log4j.version>1.2.12</log4j.version>
    <c3p0.version>0.9.1.2</c3p0.version>
    <mysql.version>8.0.19</mysql.version>
</properties>

<dependencies>
    <!-- junit单元测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

    <!-- spring beg -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.6.8</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <!-- spring对orm框架的支持包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <!-- spring end -->

    <!-- hibernate beg -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.2.1.Final</version>
    </dependency>
    <!-- hibernate end -->

    <!-- c3p0 beg -->
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>${c3p0.version}</version>
    </dependency>
    <!-- c3p0 end -->

    <!-- log end -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <!-- log end -->


    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>

    <!-- spring data jpa 的坐标-->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>1.9.0.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <!-- el beg 使用spring data jpa 必须引入 -->
    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>2.2.4</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>javax.el</artifactId>
        <version>2.2.4</version>
    </dependency>
    <!-- el end -->
</dependencies>

新建entity包,新增Customer实体类

代码语言:javascript
复制
@Entity //表示是一个实体类
@Table(name = "cst_customer") //映射的表明
public class Customer {

    @Id//声明主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)//声明主键生成策略
    @Column(name = "cust_id") //属性和字段映射
    private Long custId;
    @Column(name = "cust_name")
    private String custName;
    @Column(name = "cust_source")
    private String custSource;
    @Column(name = "cust_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;

    /**
     * 客户和联系人之间的关系,一对多关系
     * 使用注解形式配置多表关系
     * 1.声明关系:@OneToMany配置一对多关系,targetEntity对方对象的字节码对象
     * 2.配置外键(中间表):@JoinColumn,name外键字段名称,referenceColumnName参照主表的主键字段名称
     * 在客户实体类上(一对多中一的这边)添加了外键配置,对于客户而言,具备了维护外键的作用
     */

    // 联系人
    // 客户与联系人一对多关系,用@OneToMany表示
    @OneToMany(targetEntity = LinkMan.class)
    // name是指外键名,referencedColumnName是指主表的主键
    @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") // 外键配置
    private Set<LinkMan> linkManSet = new HashSet<>();

    // 此处省略getter/setter/toString方法
}

LinkMan实体类

代码语言:javascript
复制
@Entity
@Table(name = "cst_linkman")
public class LinkMan {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "lkm_id")
    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对方实体类的字节码
     * 2.配置外键(多对多使用中间表),
     * 配置外键的过程,配置到多的一方,就会在多的一方维护外键
     */
    @ManyToOne(targetEntity = Customer.class)
    @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
    private Customer customer;
    
    //此处省略getter/setter/toString方法
}    

新增dao包,增加CustomerDao接口

代码语言:javascript
复制
public interface CustomerDao extends JpaRepository<Customer,Long>,JpaSpecificationExecutor<Customer> {

}

增加LinkManDao接口

代码语言:javascript
复制
public interface LinkManDao extends JpaRepository<LinkMan, Long>, JpaSpecificationExecutor<LinkMan> {

}

resource目录下新建配置文件applicationContext.xml

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!--spring 和 spring data jpa的配置-->

    <!-- 配置包扫描-->
    <context:component-scan base-package="com.citi" ></context:component-scan>

    <!-- 1.创建entityManagerFactory对象交给spring容器管理-->
    <bean id="entityManagerFactoty" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--配置的扫描的包(实体类所在的包) -->
        <property name="packagesToScan" value="com.citi.entity" />
        <!-- jpa的实现厂家 -->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
        </property>

        <!--jpa的供应商适配器 -->
        <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>

        <!--jpa的方言 :高级的特性 -->
        <property name="jpaDialect" >
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>

        <!--
        注入jpa的配置信息
        记载jpa的基本配置信息和jpa实现方式的配置信息-->
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">create</prop>
            </props>
        </property>

    </bean>

    <!--2.创建数据库连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;amp;characterEncoding=utf8&amp;amp;autoReconnect=true&amp;amp;useSSL=false&amp;amp;serverTimezone=Asia/Shanghai" ></property>
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
    </bean>

    <!--3.整合spring dataJpa-->
    <jpa:repositories base-package="com.citi.dao" transaction-manager-ref="transactionManager"
                      entity-manager-factory-ref="entityManagerFactoty"></jpa:repositories>

    <!--4.配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactoty"></property>
    </bean>

    <!-- 4.txAdvice-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!-- 5.aop-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.citi.service.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
    </aop:config>


</beans>

在test包中新建测试类One2ManyTest,执行测试

代码语言:javascript
复制
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class One2ManyTest {

    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private LinkManDao linkManDao;

   
    // 不配置客户到联系人或者联系人到客户的关系
    @Test
    @Transactional
    @Rollback(false) //不自动回滚
    public void testSave(){
        //创建客户
        Customer customer = new Customer();
        customer.setCustName("Peter Parker");
        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("Steve");

        customerDao.save(customer);
        linkManDao.save(linkMan);
    }
}

执行的SQL语句

image.png
image.png

查看数据库,可以看到cst_linkman表的外键为空,两者没有建立关系

image.png
image.png
image.png
image.png

在One2ManyTest中增加测试方法testSave0()

代码语言:javascript
复制
// 只配置客户到联系人的关系
@Test
@Transactional
@Rollback(false) //不自动回滚
public void testSave0(){
    //创建客户
    Customer customer = new Customer();
    customer.setCustName("Peter Parker");
    LinkMan linkMan = new LinkMan();
    linkMan.setLkmName("Steve");

    // 配置customer的linkman
    customer.getLinkManSet().add(linkMan);

    customerDao.save(customer);
    linkManDao.save(linkMan);
}

只配置了客户到联系人的关系,查看执行的SQL,相比上一次测试多了一条update外键的sql语句

image.png
image.png

查看数据库表,外键已更新,关联关系已经建立

image.png
image.png

在One2ManyTest中在增加testSave1()

代码语言:javascript
复制
// 只配置联系人到客户的关系
@Test
@Transactional
@Rollback(false) //不自动回滚
public void testSave2(){
    //创建客户
    Customer customer = new Customer();
    customer.setCustName("Peter Parker");
    LinkMan linkMan = new LinkMan();
    linkMan.setLkmName("Steve");

    // 配置linkMan的customer
    linkMan.setCustomer(customer);

    customerDao.save(customer);
    linkManDao.save(linkMan);
}

只配置了联系人到客户的关系,查看执行的SQL语句,没有执行update语句,外键在insert的时候就已经建立

image.png
image.png

查看数据库表,外键存在,关联关系建立成功

image.png
image.png

在One2ManyTest中增加testSave2(),在linkMan中set customer,在customer中set linkman

代码语言:javascript
复制
@Test
@Transactional
@Rollback(false) //不自动回滚
public void testSave3(){
    //创建客户
    Customer customer = new Customer();
    customer.setCustName("Stark");
    LinkMan linkMan = new LinkMan();
    linkMan.setLkmName("Thor");

    // 配置客户到联系人的关系
    customer.getLinkManSet().add(linkMan);
    // 配置linkMan的customer
    linkMan.setCustomer(customer);

    customerDao.save(customer);
    linkManDao.save(linkMan);
}

查看执行的SQL语句

image.png
image.png

查看数据库表关系是否建立成功

image.png
image.png

通过以上四个方法的执行,testSave()无法建立customer与linkman的关联关系,testSave0()通过在customer中set linkMan可以建立两者关系,后台执行了4条sql语句(除去建表语句),testSave1()通过在linkMan中set customer也可以建立两者之间外键关系,后台执行了3条SQL语句,testSave2()通过在customer中set linkMan,同时在linkMan中set customer也可以建立两者之间的关系,后台执行了4条SQL语句,因此可以看出在一对多关系中一的一边建立外键维护关系可以执行较少的SQL语句而完成外键关系的建立,而多的一方无需拥有外键关系的维护

Customer实体类修改,mappedBy是对方配置关系的属性名称

代码语言:javascript
复制
@OneToMany(mappedBy = "customer")
private Set<LinkMan> linkManSet = new HashSet<>();

级联的概念是操作一个对象的同时操作他的关联对象 ,级联操作需要注意:

  • 需要区分操作主体
  • 需要在操作主体的实体类上,添加级联属性(需要添加到多表映射关系的注解上)
  • cascade(配置级联)

级联添加:当保存一个客户的同时保存客户的联系人

级联删除:删除一个客户的同时删除客户的联系人

级联操作测试

首先修改配置文件applicationContext.xml,将create修改为update,每次执行测试的时候不会再新建表,而是变为更新表操作

代码语言:javascript
复制
<property name="jpaProperties">
    <props>
        <prop key="hibernate.hbm2ddl.auto">update</prop>
    </props>
</property>

Customer实体类增加cascade属性

代码语言:javascript
复制
@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)
private Set<LinkMan> linkManSet = new HashSet<>();

cascade属性可以配置

  • CascadeType.All:所有操作更新保存删除都配置级联操作
  • CascadeType.MERGE:更新配置级联操作
  • CascadeType.PERSIST:保存配置级联操作
  • CascadeType.REMOVE:删除配置级联操作
  • 在One2ManyTest中新增级联添加的测试方法 ```java @Test @Transactional @Rollback(false) //不自动回滚 public void testCascadeSave(){ //创建客户 Customer customer = new Customer(); customer.setCustName("Peter"); LinkMan linkMan = new LinkMan(); linkMan.setLkmName("Stark"); // 配置客户到联系人的关系 customer.getLinkManSet().add(linkMan); // 配置linkMan的customer linkMan.setCustomer(customer); customerDao.save(customer); linkManDao.save(linkMan); }

}

代码语言:javascript
复制
![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/185e38082c2440c181ebecefe931c971~tplv-k3u1fbpfcp-watermark.image?)
数据库表
![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/74d8dd06e7814168adfb3dca1680784a~tplv-k3u1fbpfcp-watermark.image?)

![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8f7501dab39d4c70962bc6ecdcc08323~tplv-k3u1fbpfcp-watermark.image?)

在One2ManyTest中新增级联删除测试
```java
@Test
@Transactional
@Rollback(false) //不自动回滚
public void testCascadeDelete(){
    //查询客户
    Customer customer = customerDao.findOne(1L);
    customerDao.delete(customer);
}
image.png
image.png

查看数据库,两个表中都执行了删除操作

image.png
image.png
image.png
image.png
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-12-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、多表查询之一对多
    • 一对多
      • 级联操作测试
      相关产品与服务
      数据库
      云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档