1导入依赖
编写application.yml
server:
port: 8080
# Datasource
# 数据源基本配置
spring:
datasource:
username: dkx
password: dkx666
url: jdbc:mysql://localhost:3306/test_springboot_jpa?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
# hibernate.hbm2ddl.auto配置
# create:
# 每次加载hibernate时都会删除上一次的生成的表,
# 然后根据你的model类再重新来生成新表,
# 哪怕两次没有任何改变也要这样执行,
# 这就是导致数据库表数据丢失的一个重要原因。
# create-drop :
# 每次加载hibernate时根据model类生成表,
# 但是sessionFactory一关闭,表就自动删除。
# update:
# 最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构
# (前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,
# 即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,
# 表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。
# validate :
# 每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,
# 不会创建新表,但是会插入新值。
编写实体类
用户实体类和账户实体类
一个用户有多个账户(一对多)
从表(多的一方,Account)中有一列,取值参照主表的主键,这一列就是外键。
User实体类
package cn.sn.domain;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "user")//生成的表的名字
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 用的mysql,所以用IDENTITY
@Column(name = "id")//对应数据库表的列名
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "age")
private Integer age;
@OneToMany(mappedBy = "user") //放弃外键维护权,参照Account类user属性
private Set<Account> accounts = new HashSet<Account>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Set<Account> getAccounts() {
return accounts;
}
public void setAccounts(Set<Account> accounts) {
this.accounts = accounts;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", accounts=" + accounts +
'}';
}
}
账户实体类
package cn.sn.domain;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "account")
public class Account implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 用的mysql,所以用IDENTITY
@Column(name = "aid")
private Integer aid;
@Column(name = "money")
private Double money;
@ManyToOne(targetEntity = User.class)
@JoinColumn(name = "jc_id",referencedColumnName = "id")
private User user;
public Integer getAid() {
return aid;
}
public void setAid(Integer aid) {
this.aid = aid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account{" +
"aid=" + aid +
", money=" + money +
", user=" + user +
'}';
}
}
编写dao层
这里需要提到两个接口
AccountRepository接口,也就是AccountDao,换了个名字
UserRepository接口
开始测试
package cn.sn;
import cn.sn.dao.AccountRepository;
import cn.sn.dao.UserRepository;
import cn.sn.domain.Account;
import cn.sn.domain.User;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.junit4.SpringRunner;
import javax.transaction.Transactional;
@SpringBootTest
@RunWith(SpringRunner.class)
class SpringbootJpaApplicationTests {
@Autowired
private UserRepository userRepository;
@Autowired
private AccountRepository accountRepository;
/**
* 保存用户和账户信息
*/
@Test
@Transactional //开启事务
@Rollback(false)//设置为不回滚
void testSave() {
User user = new User();
user.setName("十年");
user.setAge(18);
Account account = new Account();
account.setMoney(10000.0);
user.getAccounts().add(account);
account.setUser(user);
userRepository.save(user);
accountRepository.save(account);
}
}
执行成功
级联添加
级联操作:指操作一个对象同时操作它的关联对象
使用方法:只需要在操作主体的注解上配置cascade
/**
* cascade:配置级联操作
* CascadeType.MERGE 级联更新
* CascadeType.PERSIST 级联保存:
* CascadeType.REFRESH 级联刷新:
* CascadeType.REMOVE 级联删除:
* CascadeType.ALL 包含所有
*/
@OneToMany(mappedBy="user",cascade=CascadeType.ALL)
测试一下
/**
* 级联添加操作
*/
@Test
@Transactional //开启事务
@Rollback(false)//设置为不回滚
void testSave2() {
User user = new User();
user.setName("十年");
user.setAge(19);
Account account = new Account();
account.setMoney(10000.0);
user.getAccounts().add(account);
account.setUser(user);
userRepository.save(user);//只保存一个
}
执行成功
一对多的删除操作
删除操作的说明如下:
删除从表数据:可以随时任意删除。
删除主表数据:
有从表数据
1、在默认情况下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表 结构上,外键字段有非空约束,默认情况就会报错了。
2、如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null,没有关系)因为在删除时,它根本不会去更新从表的外键字段了。
3、如果还想删除,使用级联删除引用
没有从表数据引用:随便删
在实际开发中,级联删除请慎用!(在一对多的情况下)
联级删除测试
/**
* 级联删除 删除1号用户的同时删除其账户信息
*/
@Test
@Transactional
@Rollback(false)//设置为不回滚
public void testDelete() {
userRepository.deleteById(1);
}
执行了两条删除操作
# 联级修改
如果我们给属性设置了id,将执行修改操作
如果没有设置id,将执行插入操作
我们在User中设置id,Account中不设置id。那么它会执行几条sql语句呢?
3条 1.查询出要修改数据的用户。 2.修改用户。 3.插入账户数据。
联级修改测试
/**
* 级联修改2号用户的同时修改其账户信息
*/
@Test
@Transactional
@Rollback(false)//设置为不回滚
public void testUpdate() {
User user = new User();
Account account = new Account();
user.setAge(30);
user.setName("张三");
user.setId(2);//传了id将执行修改操作
account.setMoney(88.0);
//account没有传入id,所以执行的是添加操作
user.getAccounts().add(account);
account.setUser(user);
userRepository.save(user);
}
执行成功,和我们预想的一样
先写到这里吧。
手动滑稽 "_"