您的位置:首页 > 健康 > 养生 > JPA关联MyBatis

JPA关联MyBatis

2024/10/5 20:27:21 来源:https://blog.csdn.net/Bisikl/article/details/141871864  浏览:    关键词:JPA关联MyBatis

目录

1.1 JPA多表查询

1.1.1 多表连接查询

1.1.2 关联映射

单项多对一关联

双向一对多关联

1.2 Spring Boot集成MyBatis

1.2.1 回顾MyBatis

MyBatis的优点

MyBatis的缺点

MyBatis的工作流程

1.2.2 Spring Boot集成MyBatis

MyBatis-Spring-Boot-Starter

注解配置版集成

1.1 JPA多表查询

        多表查询在Spring Data JPA中有两种实现方式,第一种是创建一个结果集的接口来接收夺标连接查询后的结果,第二种是利用JPA的关联映射来实现。

1.1.1 多表连接查询

1、创建实体类(Role、User)

@Entity
@Table(name = "sys_user")
// @NamedQueries(@NamedQuery(name = "User.findUsersByName", query = "select u from User u where u.usrName = ?1"))
@Data
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;@Column(name = "usr_role_id")private Long usrRoleId;@Column(name = "usr_flag")private Integer usrFlag;public User(String usrName, String usrPassword, Long usrRoleId, Integer usrFlag) {this.usrName = usrName;this.usrPassword = usrPassword;this.usrRoleId= usrRoleId;this.usrFlag = usrFlag;}public User() {}
}
@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 Long roleFlag;public Role() {}public Role(String roleName, String roleDesc, Long roleFlag) {this.roleName = roleName;this.roleDesc = roleDesc;this.roleFlag = roleFlag;}

 2、创建UserInfo接口,里面提供所需数据的getter方法,其中包括用户数据和角色名称(roleName)

/*** UserInfo** @author LQW* @since 2024/8/30*/
public interface UserInfo {Long getUsrId();String getUsrName();String getUsrPassword();Long getUsrRoleId();Integer getUsrFlag();// 角色名称String getRoleName();
}

3、在UserRepository中添加查询方法,返回类型设置为UserInfo

    /*** 多表查询角色名称** @param usrId* @return*/@Query("select u.usrId as usrId,u.usrName as usrName,u.usrPassword as usrPassword, u.role.roleId as usrRoleId, u.usrFlag as usrFlag, r.roleName as roleName from User u,Role r " +"where u.role.roleId = r.roleId and u.usrId = ?1")UserInfo getUserInfo(Long usrId);

4、测试验证

    @Testpublic void testGetUserInfo() {UserInfo userInfo = userRepository.getUserInfo(1L);System.out.println("usrName:" + userInfo.getUsrName());System.out.println("roleName:" + userInfo.getRoleName());}

1.1.2 关联映射

        在软件开发中,类与类之间最普遍的关系就是关联关系,而且关联是有方向的,以角色(Role)和用户(User)为例,一个角色下有多个用户,而一个用户只能属于一个角色。

        从User到Role的关联就是多对一关联,这就意味着每个User对象只会引用一个Role对象,因此在User类中应该定义一个Role类型的属性,来引用所关联的Role对象。

        从Role到User是一对多关联,这就意味着每个Role对象会引用一组User对象,因此在Role类中应该定义一个集合类型的属性,来引用所有关联的User对象。

        如果仅有从User到Role的关联,或者仅有从Role到User的关联,就称为单向关联。如果同时包含两种关联,就称为双向关联。

        数据之间一对多或者多对一的关系,通常涉及两张表,“多”方表通过外键引用“一”方表的主键来实现一对多的关联。

        本博客结合具体的例子来介绍如何映射以下关联关系:

  • 以User和Role为例,介绍如何映射多对一单向关联映射
  • 以Role和User为例,介绍如何映射一对多双向关联映射

单项多对一关联

修改User实体类,添加关联Role对象

@Entity
@Table(name = "sys_user")
// @NamedQueries(@NamedQuery(name = "User.findUsersByName", query = "select u from User u where u.usrName = ?1"))
@Data
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;// @Column(name = "usr_role_id")// private Long usrRoleId;@ManyToOne(targetEntity = Role.class)@JoinColumn(name = "usr_role_id")private Role role;@Column(name = "usr_flag")private Integer usrFlag;public User(String usrName, String usrPassword, Role role, Integer usrFlag) {this.usrName = usrName;this.usrPassword = usrPassword;this.role = role;this.usrFlag = usrFlag;}public User() {}
}

2.创建UserRepository

public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
}

3.测试基本的CRUD

    @Testpublic void testGet() {User user = userRepository.findById(1L).get();System.out.println("usrName:" + user.getUsrName());System.out.println("roleName:" + user.getRole().getRoleName());}

双向一对多关联

1.修改Role实体类,添加关联的User对象集合

@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 Long roleFlag;@OneToMany(targetEntity = User.class, fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, mappedBy = "role")private Set<User> users = new HashSet<>();public Role() {}public Role(String roleName, String roleDesc, Long roleFlag, Set<User> users) {this.roleName = roleName;this.roleDesc = roleDesc;this.roleFlag = roleFlag;this.users = users;}public Role(String roleName, String roleDesc, Long roleFlag) {this.roleName = roleName;this.roleDesc = roleDesc;this.roleFlag = roleFlag;}

2.创建RoleRepository

public interface RoleRepository extends JpaRepository<Role,Long> {
}

3.测试查询

    @Testpublic void testGet() {Role role = roleRepository.findById(1L).get();System.out.println("roleName:" + role.getRoleName());}

4.测试级联操作:级联新增

    @Testpublic void testAdd() {Role role = new Role("测试角色", "演示级联新增角色和用户", 1L);User user1 = new User("测试用户1", "123456", role, 1);User user2 = new User("测试用户2", "123456", role, 1);role.getUsers().add(user1);role.getUsers().add(user2);roleRepository.save(role);}

5.测试级联操作:级联删除

   @Testpublic void testDelete() {Role role = roleRepository.getOne(33L);roleRepository.delete(role);}

1.2 Spring Boot集成MyBatis

1.2.1 回顾MyBatis

MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集的需要。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects, 普通的Java对象)映射成数据库中的记录。

MyBatis的优点
  1. 灵活性高:MyBatis允许开发人员使用XML或注解来编写SQL语句,提供了较大的灵活性。开发人员可以根据业务需求进行定制化开发,而不必受到框架的过多限制。

  2. 性能优秀:MyBatis是一个轻量级的框架,执行速度快,并极大降低了内存使用需求。它采用轻量级的JDBC操作来进行数据库交互,从而保证了高效的性能。

  3. 易于学习和使用:MyBatis的API简单易懂,学习曲线较低,适合初学者使用。通过文档和源代码,开发人员可以比较容易地掌握它的设计思路和实现。

  4. 易于扩展:MyBatis提供了插件机制,可以方便地扩展框架的功能。开发人员可以根据自身业务量创建插件,以满足不同的业务需求。

  5. 易于与其他框架整合:MyBatis可以与Spring等框架无缝整合,提高开发效率。同时,它也支持多种数据库,如MySQL、Oracle、PostgreSQL等。

  6. 良好的可读性:MyBatis的SQL映射文件非常容易理解和修改,它们可以以更符合人类阅读习惯的方式呈现。开发人员可以使用注释、内置的逻辑标签和条件语句等方式,使代码更加清晰易懂。

  7. 提供丰富的映射标签:MyBatis支持对象与数据库的ORM字段关系映射,也支持对象关系组建维护。同时,它还提供了xml标签,支持编写动态SQL,这些都极大地提高了开发的便利性和效率。

MyBatis的缺点
  1. 需要手动编写SQL语句:相比于Hibernate等ORM框架,MyBatis需要开发人员手动编写SQL语句。对于不擅长SQL的开发人员来说,可能会增加开发成本。

  2. SQL映射复杂:虽然MyBatis提供了灵活的SQL映射方式,但这也意味着需要开发者自己解决一些查询语句上的问题。在复杂场景下,可能需要较高的SQL能力才能完成正确的映射。

  3. XML配置维护困难:MyBatis的配置文件需要通过XML来进行书写,这种方式与Java代码相比可能不够直观。随着项目规模的增大,配置文件可能会变得十分庞大且难以维护。

  4. 编码效率较低:由于需要手动编写SQL查询语句和参数映射,MyBatis对开发人员的编码技术要求较高。这可能会增加开发工作量并降低开发效率。

  5. 缺乏自动化的数据库操作机制:MyBatis没有提供自动化的数据库操作机制,开发人员需要手动处理对象和数据库之间的映射关系。这可能会增加开发的复杂性和出错的可能性。

  6. 社区和文档支持相对较弱:尽管MyBatis是一个流行的ORM框架,但与其他一些框架相比,其中文资料较少且不清晰,同时社区活跃度也相对较低。这可能会给开发者在使用过程中带来一些不便。

MyBatis的工作流程

1. 加载配置文件

MyBatis首先会加载全局配置文件(如mybatis-config.xml),这个文件包含了MyBatis的运行环境信息,如数据源、事务管理器、类型别名、插件等配置。同时,MyBatis还会加载SQL映射文件(如mapper.xml),这些文件配置了与数据库操作相关的SQL语句和映射规则。

2. 构造会话工厂

通过读取配置文件的信息,MyBatis会构造出一个会话工厂(SqlSessionFactory)。这个工厂是创建会话(SqlSession)的工厂类,它包含了数据库连接池等重要的数据库连接信息。

3. 创建会话

通过会话工厂,MyBatis可以创建出会话对象(SqlSession)。SqlSession是MyBatis的核心接口,它提供了执行SQL命令所需的所有方法,如增删改查等。每个线程都应该有它自己的SqlSession实例,因为SqlSession不是线程安全的。

4. 创建执行器

虽然SqlSession提供了数据库操作的方法,但它本身并不直接操作数据库。相反,它使用了一个叫做执行器(Executor)的接口来执行数据库操作。执行器是MyBatis的核心,它负责SQL语句的生成和查询缓存的维护。MyBatis提供了多种执行器实现,如SimpleExecutorReuseExecutorBatchExecutor等,以满足不同的执行需求。

5. 封装SQL对象

在执行SQL语句之前,MyBatis会将待处理的SQL信息封装到一个MappedStatement对象中。这个对象包含了SQL语句、输入参数映射信息(如Java简单类型、HashMap或POJO)和输出结果映射信息(如Java简单类型、HashMap或POJO)。这样,MyBatis就可以根据这些信息来动态地生成SQL语句,并执行它。

6. 操作数据库

拥有了执行器和SQL信息封装对象后,MyBatis就可以使用它们来访问数据库了。执行器会根据MappedStatement对象中的信息来生成SQL语句,并设置参数,然后执行这个SQL语句。执行完成后,MyBatis还会根据结果映射信息将结果集映射成Java对象,并返回给调用者。

7. 释放资源

在操作完成后,MyBatis会释放数据库连接等资源,以确保资源的有效利用和避免资源泄露。

1.2.2 Spring Boot集成MyBatis

MyBatis-Spring-Boot-Starter

1.创建项目

 

2.pom.xml文件配置依赖项

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.18</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><version>3.3.3</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency>

3.application.properties 配置相关信息

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/crm_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC  
spring.datasource.username=root
spring.datasource.password=luoqiangwumybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
mybatis.type-aliases-package=com.bdqn.mybatis_spring_boot.entitylogging.level.root=warn
logging.level.com.bdqn.mybatis_spring_boot.mapper=trace
logging.pattern.console=%p%m%n

4.启动类

@SpringBootApplication
@MapperScan("com.bdqn.mybatis_spring_boot.mapper")
public class MyBatisSpringBootApplication {public static void main(String[] args) {SpringApplication.run(MyBatisSpringBootApplication.class, args);}}

5.编码

配置一些全局属性

    <!-- 全局配置文件 --><settings><!-- 开启二级缓存 --><setting name="cacheEnabled" value="true" /><!-- 开启控制台日志 --><setting name="logImpl" value="STDOUT_LOGGING" /><setting name="lazyLoadingEnabled" value="true" /><!--全自动映射级别--><setting name="autoMappingBehavior" value="FULL" /></settings>

编写Mapper接口

public interface UserMapper {void insert(User user);void delete(Long id);void update(User user);User get(Long id);List<User> findAll();
}

编写UserMapper.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bdqn.mybatis_spring_boot.mapper.UserMapper"><resultMap id="UserResultMap" type="com.bdqn.mybatis_spring_boot.entity.User"><id column="usr_id" property="usrId" /><result column="usr_name" property="usrName" /><result column="usr_password" property="usrPassword" /><result column="usr_role_id" property="usrRoleId" /><result column="usr_flag" property="usrFlag" /></resultMap><sql id="columns">usr_id,usr_name,usr_password,usr_role_id,usr_flag</sql><insert id="insert">insert into sys_user(usr_name, usr_password, usr_role_id, usr_flag)values (#{usrName}, #{usrPassword}, #{usrRoleId}, #{usrFlag})</insert><update id="update">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></set>where usr_id = #{usrId}</update><delete id="delete">deletefrom sys_userwhere usr_id = #{usrId}</delete><select id="get" resultMap="UserResultMap">select<include refid="columns" />from sys_userwhere usr_id = #{usrId}</select><select id="findAll" resultMap="UserResultMap">select<include refid="columns" />from sys_user</select>
</mapper>

6.测试

@SpringBootTest
public class UserMapperTester {@Resourceprivate UserMapper userMapper;@Testpublic void testInsert(){userMapper.insert(new User("ktjiaoyu","123453",2L,1));}@Testpublic void testGet(){User user = userMapper.get(2L);System.out.println("usrName:"+user.getUsrName());}@Testpublic void testDelete(){userMapper.delete(88L);}@Testpublic void testUpdate(){userMapper.update(new User(90L,"JPA","12345",1L,1));}@Testpublic void testSelect(){List<User> all = userMapper.findAll();for (User user : all){System.out.println(user);}}
}
注解配置版集成

给Mapper接口内添加注解

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 \n" +"        from sys_user \n" +"        where usr_id = #{usrId}")void delete(Long id);@Update("<script>" + "update sys_user \n" +"        <set> \n" +"            <if test=\"usrName != null\">usr_name = #{usrName},</if> \n" +"            <if test=\"usrPassword != null\">usr_password = #{usrPassword},</if> \n" +"            <if test=\"usrRoleId != null\">usr_role_id = #{usrRoleId},</if> \n" +"            <if test=\"usrFlag != null\">usr_flag = #{usrFlag},</if> \n" +"        </set> \n" +"        where usr_id = #{usrId}" +"</script>")void update(User user);//@Select("select \n" +"         usr_id,usr_name,usr_password,usr_role_id,usr_flag\n" +"        from sys_user \n" +"        where usr_id = #{usrId}")@Results({@Result(column = "usr_id", property = "usrId"),@Result(column = "usr_name", property = "usrName"),@Result(column = "usr_password", property = "usrPassword"),@Result(column = "usr_role_id", property = "usrRoleId"),@Result(column = "usr_flag", property = "usrFlag")})User get(Long id);@Select("select \n" +"        usr_id,usr_name,usr_password,usr_role_id,usr_flag \n" +"        from sys_user")@Results({@Result(column = "usr_id", property = "usrId"),@Result(column = "usr_name", property = "usrName"),@Result(column = "usr_password", property = "usrPassword"),@Result(column = "usr_role_id", property = "usrRoleId"),@Result(column = "usr_flag", property = "usrFlag")})List<User> findAll();}

(注意:使用注解配置版集成要先把UserMapper.xml里面的sql注释才能运行成功,不然会报错!!!)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com