JPA关联mybatis
一、JPA 关联
-
实体关系映射:
- JPA 支持多种实体间的关联关系,如一对一、一对多、多对一和多对多。通过使用注解可以清晰地定义实体之间的关系,方便进行数据库操作时自动处理关联数据的加载和保存。
- 例如,使用
@OneToOne
、@OneToMany
、@ManyToOne
和@ManyToMany
注解来分别表示不同的关联关系。
单向多对一关联:
@Entity
@Table(name = "sys_user")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "usr_id")
private Long usrId;
@Column(name = "usr_name")
private String usrName;
@Column(name = "usr_password")
private String usrPassword;
@ManyToOne(targetEntity = Role.class)
@JoinColumn(name = "usr_role_id")
private Role role;
@Column(name = "usr_role_id")
private Long usrRoleId;
@Column(name = "usr_flag")
private Integer usrFlag;
@OneToMany:注解映射多对一关联关系,targetEntity属性表示关联实体类型;可省略
@JoinColumn:注解映射关联的外键字段,如不指定,则生成一张新表维护俩个对象之间的关系
双向一对多关联:
@Entity
@Table(name="sys_role")
@Data
public class Role implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "role_id")
private Long roleId;
@Column(name = "role_name")
private String roleName;
@Column(name = "role_desc")
private String roleDesc;
@Column(name = "role_flag")
private Integer roleFlag;
@OneToMany(targetEntity = User.class,fetch = FetchType.EAGER,cascade = CascadeType.REMOVE,mappedBy = "role")
private Set<User> users = new HashSet<>();
targetEntity :属性表示关联的实体类型
fetch :属性表示加载策略,FetchType 取值有 LAZY及 EAGER,LAZY 表示延迟加载EAGER表示立即加载。@ManyTo0ne注解也包含该属性,且默认值为EAGER,表示立即加载,所以查询 User 时通过左外关联立即获取 Role 数据;@OneToMany 注解该属性默认值为 LAZY。
cascade: 属性表示级联操作,CascadeType取值有PERSIST、REMOVE、ALL…等PERSIST 表示级联持久化(保存)操作,REMOVE级联删除,ALL级联所有操作@ManyToOne 注解也包含该属性,但一般不在多的一方进行级联操作。
mappedBy: 属性用来设置对象之间的关系维护方(关系维护通过操作外键完成)。如不指定 mappedBy 属性,则对象均由自己维护关系(外键),操作一方对象时,会额外产生更新外键的SQL语句。所以一般在@OneToMany注解中指定 mappedBy 属性且属性值为多方对象中关联的一方属性名,并且此时一方实体中不能添加@JoinColumn 注解。
二、MyBatis
-
灵活的 SQL 映射:
MyBatis 以 SQL 为中心,允许开发者编写灵活的 SQL 语句来进行数据库操作。可以根据具体的业务需求定制复杂的查询、插入、更新和删除操作。
通过 XML 配置文件或注解的方式,将 SQL 语句与 Java 方法进行映射,使得数据库操作更加直观和易于维护。
-
结果映射:
MyBatis 提供了强大的结果映射功能,可以将数据库查询结果映射到 Java 对象中。可以通过自定义结果映射器或使用自动映射功能来简化对象的创建和数据的填充。
例如,可以使用 resultMap
标签来定义复杂的结果映射规则,将数据库表中的列映射到 Java 对象的属性上。
-
动态 SQL:
MyBatis 支持动态 SQL,可以根据不同的条件生成不同的 SQL 语句。这在处理复杂的查询条件和动态生成 SQL 时非常有用。
使用 <if>
、<choose>
、<when>
、<otherwise>
等标签可以根据条件动态地拼接 SQL 语句,提高 SQL 的灵活性和可维护性。
-
插件扩展:
MyBatis 提供了插件机制,可以方便地扩展其功能。开发者可以编写自定义插件来实现诸如分页、缓存、日志记录等功能。
通过实现 Interceptor
接口,可以在 MyBatis 的执行过程中插入自定义的逻辑,增强框架的功能。
-
优点:
- SQL 被统一提取出来,便于统一管理和优化
- SQL和代码解耦,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰、更易维护、更易单元测试
- 提供映射标签,支持对象与数据库的 ORM 字段关系映射
- 提供对象关系映射标签,支持对象关系组件维护
- 灵活书写动态SQL,支持各种条件来动态生成不同的SQL
-
缺点:
- 提供对象关系映射标签,支持对象关系组件维护
- SQL语句依赖于数据库,导致数据库移植性差
三.MyBatis 与 Spring Boot 集成
集成 MyBatis 和 Spring Boot 可以利用 Spring Boot 提供的自动配置功能,使得配置和使用 MyBatis 更加便捷。以下是集成的步骤和要点:
2.1 添加依赖
在 Spring Boot 项目的 pom.xml
文件中添加 MyBatis 和数据库驱动的依赖:
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- MyBatis Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mybatis</artifactId>
</dependency>
<!-- 数据库驱动(例如 MySQL) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
2.2 配置数据源
在 application.properties
或 application.yml
文件中配置数据源属性:
application.properties
示例:
mybatis.type-aliases-super-type=com.bdqn.t369spingboot.entity.User
spring.application.name=T369-Spring-Boot
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/crm?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
mybatis.config-location=classpath:mybatis/mybatis-config.xml
#mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
mybatis.type-aliases-package=com.bdqn.t369spingboot.entity
logging.level.root=warn
logging.level.com.bdqn.t369spingboot.mapper=trace
logging.pattern.console=%p%m%n
#??JPA(Hibernate)????
#spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
2.3 创建实体类
定义与数据库表对应的实体类:
public class User implements Serializable {
private Long usrId;
private String usrName;
private String usrPassword;
private Long usrRoleId;
private Integer usrFlag;
2.4 创建 Mapper 接口
定义 Mapper 接口并标注 @Mapper
注解(如果使用 Spring Boot 2.0 或更高版本,可以省略 @Mapper
注解):
package com.bdqn.t369spingboot.mapper;
import com.bdqn.t369spingboot.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserMapper {
@Insert("INSERT INTO sys_user(usr_name, usr_password, usr_role_id, usr_flag) " +
"VALUES(#{usrName}, #{usrPassword}, #{usrRoleId}, #{usrFlag})")
void insert(User user);
@Delete("DELETE FROM sys_user WHERE usr_id = #{id}")
void delete(Long id);
@Update("<script>" +
"UPDATE sys_user SET " +
"<if test=\"usrName != null\">usr_name = #{usrName}, </if>" +
"<if test=\"usrPassword != null\">usr_password = #{usrPassword}, </if>" +
"<if test=\"usrRoleId != null\">usr_role_id = #{usrRoleId}, </if>" +
"<if test=\"usrFlag != null\">usr_flag = #{usrFlag}</if>" + // 移除最后一个逗号
"WHERE usr_id = #{usrId}" +
"</script>")
void update(User user);
@Select("SELECT usr_id, usr_name, usr_password, usr_role_id, usr_flag FROM sys_user WHERE usr_id = #{id}")
@Results({
@Result(property = "usrId", column = "usr_id"),
@Result(property = "usrName", column = "usr_name"),
@Result(property = "usrPassword", column = "usr_password"),
@Result(property = "usrRoleId", column = "usr_role_id"),
@Result(property = "usrFlag", column = "usr_flag")
})
User get(Long id);
@Select("SELECT usr_id, usr_name, usr_password, usr_role_id, usr_flag FROM sys_user")
@Results({
@Result(property ="usrId", column = "usr_id"),
@Result(property ="usrName", column = "usr_name"),
@Result(property ="usrPassword", column = "usr_password"),
@Result(property ="usrRoleId", column = "usr_role_id"),
@Result(property ="usrFlag", column = "usr_flag")
})
List<User> findAll();
}
2.5 编写测试类
@RunWith(SpringRunner.class)
@SpringBootTest(classes = T369SpingBootApplication.class)
public class UserMapperTester {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert() throws Exception{
userMapper.insert(new User("ktjiaoyu","123456",2L,1));
}
@Test
public void testGet(){
User user = userMapper.get(2L);
System.out.println("usrName:"+user.getUsrName());
}
总的来说,JPA 关联提供了强大的实体关系管理和自动处理关联数据的能力,适合于以对象为中心的开发模式。而 MyBatis 则更加灵活,以 SQL 为中心,适合于对 SQL 有较高要求和需要进行复杂数据库操作的场景。