SpringDataJPA
前言
ORM思想
主要目的:操作实体类就相当于操作数据库表
建立两个映射关系
实体类和表的映射关系
实体类中属性和表中字段的映射关系
不再重点关注 sql 语句
实现了 orm 思想的框架有 mybatis, hibernate
什么是 hibernate ?
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它
将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate 可以自动生成SQL语
旬,自动执行,使得Java程序员可以随心所欲的使用对象編程思维来操纵数据库。
JPA
JPA的全称是Java Persistence API,即Java持久化API,是SUN公司推出的一套基于ORM
的规范,内部是由一系列的接口和抽象类构成。
JPA通过JDK 5.0注解描述对象-->关系表的映射关系,并将运行期的实体对象持久化到数据库中。
优势:
JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以
看成是Hibernate HQL的等价物。JPA定义了独特的JPQL (Java Persistence query
Language),JPQL 是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而
不是关系数据库的表,而且能够支持批量更新和修改、JOIN、 GROUP BY、HAVING 等通常只有
SQL才能够提供的高级查询特性,甚至还能够支持子查询。
hiberate 入门
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.3.7.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.3.7.Final</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
jpa 核心配置文件
src/META-INF/persistence.xml
<?xml version="1.0" encoding="utf-8" ?>
<!--导入schema约束,此约束来源:复制hibernate-core:5.2.16.Final包下的/org/hibernate/jpa/persistence_2_0.xsd文件中的这一段出来即可。 -->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<!--配置持久化单元(可以配置多个,名称不能重复)
name:用于指定持久化单元的名称
transcation-type:指定事务的类型。
JTA:Java
Transcation API RESOURCE_LOCAL:指的是本地代码事务 -->
<persistence-unit name="myPersistenceUnit"
transaction-type="RESOURCE_LOCAL">
<!--JPA规范提供商,可以不写 -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!--指定Jpa注解的实体类型位置,可以不写
<class>com.demo.domain.Customer</class>
连接相关的一些配置,都是用hibernate的。 -->
<properties>
<!--第一部分,连接数据库信息 -->
<property name="hibernate.connection.driver_class"
value="com.mysql.jdbc.Driver"></property>
<property name="hibernate.connection.url"
value="jdbc:mysql://127.0.0.1:3306/data?characterEncoding=utf8"></property>
<property name="hibernate.connection.username" value="root"></property>
<property name="hibernate.connection.password" value="123"></property>
<!--说明:数据库的方言,用于存放不同数据库之间的SQL语句差异。 -->
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQL57Dialect"></property>
<!--第二部分,hibernate的可选配置 -->
<!--是否显示hiberante的生成的SQL语句 -->
<property name="hibernate.show_sql" value="true"></property>
<!--是否使用格式化输出SQL语句到控制台 -->
<property name="hibernate.format_sql" value="false"></property>
<!--采用何种方式生成DDL语句,
create: 程序运行时先删除表,在创建表
update 程序运行时创建表,如果有表则不创建
不一致,则更新数据库。 -->
<property name="hibernate.hbm2ddl.auto" value="update"></property>
<!--连接池的配置,这里使用的是c3p0连接池,常用的还有阿里的 -->
<property name="hibernate.connection.provider_class"
value="org.hibernate.c3p0.internal.C3P0ConnectionProvider"></property>
</properties>
</persistence-unit>
</persistence>
User.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity // 声明实体类
@Table(name = "user")
public class User {
@Id // 主键自增
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "username")
private String username;
private String password;
@Column(name = "create_time")
private Date createTime;
}
main.java
public class AppTest {
public static void main(String[] args) {
// 读取配置文件,创建实体管理器工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("myPersistenceUnit");
// 获取实体管理器
EntityManager em = factory.createEntityManager();
// 获取事务对象
EntityTransaction tx = em.getTransaction();
// 开启事务
tx.begin();
// 保存一个用户到数据库
User user = new User();
user.setUsername("bingbing");
user.setPassword("456");
// 保存
em.persist(user);
// 提交事务
tx.commit();
// 释放资源
em.close();
factory.close();
}
}
EntityManagerFactory :获取EntityManager对象
方法: createEntityManager 内部维护的很多的内容
内部维护了数据库信息,
维护了缓存信息
维护了所有的实体管理器对象
再创建EntityManagerFactory的过程中会根据配置创建数据库表
当EntityManagerFactory的创建过程比较浪费资源
特点:线程安全的对象
多个线程访间同一个EntityManagerFactory不会有线程安全间题
*如何解决EntityManagerFactory的创建过程浪费资源(耗时)的问题?
思路:创建一个公共的EntityManagerFactory的对象
*静态代码块的形式创建EntityManagerractory
创建事务对象,开启事务
EntityManagex对象:实体类管理器
beginTransaction :创建事务对象
presist :保存
merge
更新
remove :删除
find/JetRefrence :
根据id查询
4.增删改查操作
5.提交事务
6.释放资源
JpaUtil 工具类
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class JpaUtils {
private static final EntityManagerFactory factory;
private JpaUtils() {
}
static {
factory = Persistence.createEntityManagerFactory("myPersistenceUnit");
}
public static EntityManager getEntityManager() {
return factory.createEntityManager();
}
public static void close() {
factory.close();
}
}
简单CRUD
// 新增
public static void main(String[] args) {
EntityManager em = JpaUtils.getEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
User user = new User();
user.setUsername("huihui");
user.setPassword("233");
// insert into user (create_time, password, username) values (?, ?, ?)
em.persist(user);
tx.commit();
em.close();
}
// 查询
public static void main(String[] args) {
EntityManager em = JpaUtils.getEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// 根据id查询数据
User user = em.find(User.class, 1);
System.out.println(user);
tx.commit();
em.close();
}
// 删除
public static void main(String[] args) {
EntityManager em = JpaUtils.getEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// find
User user = em.find(User.class, 3);
// delete from user where id=?
em.remove(user);
tx.commit();
em.close();
}
// 更新
public static void main(String[] args) {
EntityManager em = JpaUtils.getEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// find
User user = em.find(User.class, 4);
user.setPassword("789");
// update user set create_time=?, password=?, username=? where id=?
em.merge(user);
tx.commit();
em.close();
}
延迟加载与立即加载
// 立即加载
// 根据 id 查询数据
// 立即发送 sql 查询数据
User user = em.find(User.class, 1);
System.out.println(user);
// 延迟加载
// 根据 id 查询数据
// 不会立即发送 sql 查询数据,当在使用到 u2 对象时再查询数据
User u2 = em.getReference(User.class, 2);
System.out.println(u2);
复杂CRUD
JPQL
JPQL全称Java Persistence Query Language
基于首次在EJB2.0中引入的EJB查询语言(EJB QL) , Java持久化查询语言(JPQL)是一种可移
植的查询语言,旨在以面向对象表达式语言的表达式,将SQL语法和简单查询语义绑定在一起使
用这种语言编写的查询是可移植的,可以被編译成所有主流数据库服务器上的SQL
其特征与原生SQL语句类似,并且完全面向对象,通过类名和属性访问,而不是表名和表的属性。
SQL查询的是表和表中的字段
JPQL查询的是实体类和类中的属性
// 查询全部
public static void main(String[] args) {
EntityManager em = JpaUtils.getEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// 查询全部
// String jpql = "from cn.liuweiwei.domain.User";
String jpql = "from User";
Query query = em.createQuery(jpql);
@SuppressWarnings("unchecked")
List<User> users = query.getResultList();
users.forEach(user -> System.out.println(user));
tx.commit();
em.close();
}
// 倒序
String jpql = "from User order by id desc";
// 统计查询
public static void main(String[] args) {
EntityManager em = JpaUtils.getEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// 统计查询
String jpql = "select count(id) from User";
Query query = em.createQuery(jpql);
Object count = query.getSingleResult();
System.out.println(count);
tx.commit();
em.close();
}
// 分页查询
public static void main(String[] args) {
EntityManager em = JpaUtils.getEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// 分页查询
String jpql = "from User";
Query query = em.createQuery(jpql);
// limit ?, ? (limit 起始索引, 每页条数)
// 起始索引
query.setFirstResult(0);
// 每页条数
query.setMaxResults(2);
@SuppressWarnings("unchecked")
List<User> users = query.getResultList();
users.forEach(user -> System.out.println(user));
tx.commit();
em.close();
}
// 条件查询
public static void main(String[] args) {
EntityManager em = JpaUtils.getEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
// 条件查询
// 查询用户名中包含 i 的数据
String jpql = "from User where username like ?0";
Query query = em.createQuery(jpql);
// 设置第一个参数
// 方法的第一个参数对应占位符后的数字
query.setParameter(0, "%i%");
@SuppressWarnings("unchecked")
List<User> users = query.getResultList();
users.forEach(user -> System.out.println(user));
tx.commit();
em.close();
}
// 条件查询
// 查询 id > 3 的数据
String jpql = "from User where id > ?1";
Query query = em.createQuery(jpql);
query.setParameter(1, 3);
@SuppressWarnings("unchecked")
List<User> users = query.getResultList();
users.forEach(user -> System.out.println(user));
SpringDataJPA
Spring Data JPA是Spring基于ORM框架、JPA 规范的基础上封装的一套 JPA应用框架,可使开
发者用极简的代码即可实现对数据库的访问和操作。它提供了包括增删改查等在内的常用功能,且
易于扩展!学习并使用Spring Data JPA可以极大提高开发效率。
Spring Data JPA 让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现,在实际的
工作工程中,推荐使用Spring Data JPA + ORM (如,hibernate) 完成操作,这样在切换不同的ORM
框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦。
springData Jpa 极大简化了数据库访问层代码。如何简化的呢? 使用了SpringDataJpa,
我们的dao层中只需要写接口,就自动具有了增删改查、分页查询等方法。
SpringDataJPA, Hibernate JPA 的关系
JPA是一套规范,内部是有接口和抽象类组成的。hibernate 是一套成熟的ORM框架,而且
Hibernate实现了JPA规范,所以也可以称hibernate为JPA的一种实现方式,我们使用JPA
的API编程,意味着站在更高的角度上看待问题(面向接口编程)。
Spring Data JPA是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下的专门
用来进行数据持久化的解决方案。
pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.3.7.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.3.7.Final</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
applicationContext.xml
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--1 配置数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver" />
<property name="username" value="root" />
<property name="password" value="123" />
<property name="url" value="jdbc:mysql://localhost:3306/data?characterEncoding=utf8" />
</bean>
<!--2 配置EntityManagerFactory -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<!-- 配置实体类所在的包 -->
<property name="packagesToScan" value="cn.liuweiwei.domain" />
<property name="jpaProperties">
<props>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!--3 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>
<!--4 配置支持注解的事务 -->
<tx:annotation-driven
transaction-manager="transactionManager" />
<!--5 配置接口所在的包 -->
<jpa:repositories base-package="cn.liuweiwei.mapper"
entity-manager-factory-ref="entityManagerFactory" />
<!-- 包扫描 -->
<context:component-scan base-package="cn.liuweiwei" />
</beans>
实体类和测试
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private String password;
@Column(name = "create_time")
private Date createTime;
// seter/geter...
}
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import cn.liuweiwei.domain.User;
/*
* JpaRepository 封装了基本查询
* JpaSpecificationExecutor 封装了复杂查询
* */
public interface UserMapper extends JpaRepository<User, Integer>, //
JpaSpecificationExecutor<User> {
}
测试
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AppTest {
@Autowired
private UserMapper userMapper;
@Test
public void contextApp() {
Optional<User> optional = userMapper.findById(1);
User user = optional.get();
System.out.println(user);
}
}
简单CRUD
// 查询
@Test
public void contextApp() {
// 根据 id 查询数据
Optional<User> optional = userMapper.findById(1);
User user = optional.get();
System.out.println(user);
}
// 查询所有
@Test
public void testFindAll() {
List<User> users = userMapper.findAll();
users.forEach(user -> System.out.println(user));
}
// 统计查询
@Test
public void testCount() {
System.out.println(userMapper.count());
// 判断 id 为 4的数据是否存在
System.out.println(userMapper.existsById(4)); // true
}
// 保存或更新
@Test
public void testSave() {
User user = new User();
user.setUsername("huahua");
user.setPassword("789");
// 更新或保存一条数据
// 如果 id 为空就保存,否则就更新
userMapper.save(user);
}
// 删除
@Test
public void testDelete() {
userMapper.deleteById(6);
}
JPQL CRUD
public interface UserMapper extends JpaRepository<User, Integer>, //
JpaSpecificationExecutor<User> {
@Query("from User where username = ?1")
User findByName(String username);
@Query("from User")
List<User> findAllUser();
@Query("from User where username = ?1 and password = ?2")
User findOne(String username, String password);
@Query("from User where username like ?1")
List<User> likeFind(String username);
@Modifying
@Transactional
@Query("update User set username = ?1 where id = ?2")
void updateUser(String username, Integer id);
@Modifying
@Transactional
@Query("delete from User where id = ?1")
void deleteUser(Integer id);
}
方法名规则映射查询
User findByUsername(String username);
List<User> findByUsernameLike(String username);
User findByUsernameLikeAndPassword(String username, String password);
动态查询
@Test
public void testFindOne() {
/*
* 自定义查询条件
* 实现 Specification接口(提供泛型,查询的对象类型)
* 实现 toPredicate 方法(构造查询条件)
* 借助方法中的两个参数
* root:获取需要查询的对象属性
* criteriaBuilder:构造查询条件,模糊/精准匹配
*/
@SuppressWarnings("serial")
Specification<User> spec = new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, //
CriteriaBuilder criteriaBuilder) {
// 获取比较属性
Path<Object> password = root.get("password");
// 构造查询条件
return criteriaBuilder.equal(password, "123");
}
};
Optional<User> optional = userMapper.findOne(spec);
System.out.println(optional.get());
}
多条件拼接
@Test
public void testFindOneBySelect() {
@SuppressWarnings("serial")
Specification<User> spec = new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, //
CriteriaBuilder criteriaBuilder) {
Path<Object> username = root.get("username");
Path<Object> password = root.get("password");
return criteriaBuilder.and(criteriaBuilder.equal(username, "vivivi"),//
criteriaBuilder.equal(password, "123"));
}
};
System.out.println(userMapper.findOne(spec).get());
}
排序
@Test
public void testSort() {
// 根据 id 降序排序
userMapper.findAll(new Sort(Direction.DESC, "id")) //
.forEach(user -> System.out.println(user));
}
分页
@Test
public void testPage() {
Page<User> page = userMapper.findAll(PageRequest.of(0, 2));
List<User> users = page.getContent();
users.forEach(user -> System.out.println(user));
}
多表查询
一对多
Customer.java
@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "c_id")
private Integer id;
private String name;
// 行业
private String industry;
private String phone;
private String address;
// @OneToMany(targetEntity = Linker.class)
// @JoinColumn(name = "cust_id", referencedColumnName = "c_id")
@OneToMany(mappedBy = "customer") // 放弃外键维护权
private List<Linker> linkers = new ArrayList<>();
// seter/geter...
}
Linker.java
@Entity
@Table(name = "linker")
public class Linker {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String phone;
private String gender;
private String position;
@ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "cust_id", referencedColumnName = "c_id")
private Customer customer;
// seter/geter...
}
Test
@Test
@Transactional
@Rollback(false)
public void testSave() {
Customer customer = new Customer();
customer.setName("字节跳动");
customer.setPhone("110");
customer.setIndustry("互联网");
customer.setAddress("北京市朝阳区");
Linker linker = new Linker();
linker.setName("冰冰");
linker.setGender("女");
linker.setPhone("112");
linker.setPosition("前端工程师");
// 建立联系
linker.setCustomer(customer);
// 保存
customerMapper.save(customer);
linkerMapper.save(linker);
}
级联删除
删除从表数据:可以随时任意删除。
删除主表数据:。
有从表数据。
1、在默认情况下,它会把外健字段置为null, 然后删除主表数据。如果在数据库的表
结构上,外键字段有非空約東,默认情况就会报错了。
2、如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null,没
有关系)因为在删除时,它根本不会去更新从表的外键字段了。
3、如果还想删除,使用级联删除引用。
没有从表数据引用,随便删。
在实际开发中,级联删除请慎用! (在一对多的情况下)。
// cascade = CascadeType.ALL 配置级联
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
private List<Linker> linkers = new ArrayList<>();
@Test
public void testDelete() {
// 级联删除
customerMapper.delete(customerMapper.findById(1).get());
}
多对多
Person.java
@Entity
@Table(name = "person")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "p_id")
private Integer id;
private String username;
private String password;
// 配置用户到角色多对多
// fetch = FetchType.EAGER 关闭延迟加载
@ManyToMany(targetEntity = Role.class, //
cascade = CascadeType.ALL, //
fetch = FetchType.LAZY)
// 配置中间表,包含两个外键
@JoinTable(
// 中间表名
name = "person_role",
// 当前对象 Person 在中间表中的外键
joinColumns = { //
@JoinColumn(name = "sys_p_id", referencedColumnName = "p_id") //
},
// 对方对象 Role 在中间表中的外键
inverseJoinColumns = { //
@JoinColumn(name = "sys_r_id", referencedColumnName = "r_id")//
}//
)
private List<Role> roles = new ArrayList<Role>();
// getter.setter...
// 注意 toString() 中不能包含 roles 属性
@Override
public String toString() {
return "Person [id=" + id + ", username=" + username + ", password=" + password + "]";
}
}
Role.java
@Entity
@Table(name = "role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "r_id")
private Integer id;
private String name;
// 配置角色到用户多对多
@ManyToMany(mappedBy = "roles", //
cascade = CascadeType.ALL, //
fetch = FetchType.LAZY)
private List<Person> persons = new ArrayList<Person>();
// getter/setter...
// 注意这个 toString() 方法,不能打印 person 属性!!!
// 否则会出现 stackoverflow !!
@Override
public String toString() {
return "Role [id=" + id + ", name=" + name + "]";
}
}
Test.java
@Test
@Transactional
@Rollback(false)
public void testSave() {
Person person = new Person();
person.setUsername("冰冰");
person.setPassword("233");
Role role = new Role();
role.setName("前端工程师");
// 关联关系
person.getRoles().add(role);
personMapper.save(person);
roleMapper.save(role);
}
@Test
@Transactional // 必须加这个注解才能使延迟加载过程中不关闭 session
public void testFindById() {
Person person = personMapper.findById(1).get();
// List<Role> roles = person.getRoles();
System.out.println(person);
}