当前位置: 首页 > news >正文

MyBatis —— 多表操作和注解开发

一、前言

本文需要导入的坐标如下:

  <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version><scope>test</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.32</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>3.7.5</version></dependency><dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>0.9.1</version></dependency></dependencies>

核心配置文件如下:

<configuration><!--通过properties标签加载外部properties文件--><properties resource="jdbc.properties"/><!--取别名--><typeAliases><typeAlias type="com.yds.domain.User" alias="user"/><typeAlias type="com.yds.domain.Order" alias="order"/><typeAlias type="com.yds.domain.Role" alias="role"/></typeAliases><!--配置数据源环境--><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--加载映射文件--><mappers><mapper resource="com.yds.mapper/UserMapper.xml"/><mapper resource="com.yds.mapper/OrderMapper.xml"/></mappers></configuration>

二、多表操作

首先我们需要创建四个表,分别是user、role、orders、user_role。

user表:

orders表:

role表:

user_role表(中间表):

然后需要创建对应的实体pojo:

User类:

public class User {private int id;private String username;private String password;private Date birthday;//描述的是当前用户存在哪些订单private List<Order> orderList;//描述的是当前用户均被哪些角色private List<Role> roleList;public List<Role> getRoleList() {return roleList;}public void setRoleList(List<Role> roleList) {this.roleList = roleList;}public List<Order> getOrderList() {return orderList;}public void setOrderList(List<Order> orderList) {this.orderList = orderList;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", birthday=" + birthday +", orderList=" + orderList +", roleList=" + roleList +'}';}
}

Oder类:

public class Order {private int id;private Date ordertime;private double total;//当前订单属于哪一个用户private User user;public int getId() {return id;}public void setId(int id) {this.id = id;}public Date getOrderTime() {return ordertime;}public void setOrderTime(Date orderTime) {this.ordertime = orderTime;}public double getTotal() {return total;}public void setTotal(double total) {this.total = total;}public User getUser() {return user;}public void setUser(User user) {this.user = user;}@Overridepublic String toString() {return "Order{" +"id=" + id +", orderTime=" + ordertime +", total=" + total +", user=" + user +'}';}
}

Role类:

public class Role {private int id;private String roleName;private String roleDesc;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}public String getRoleDesc() {return roleDesc;}public void setRoleDesc(String roleDesc) {this.roleDesc = roleDesc;}@Overridepublic String toString() {return "Role{" +"id=" + id +", roleName='" + roleName + '\'' +", roleDesc='" + roleDesc + '\'' +'}';}
}

1.一对一查询

我们设置一个情景:一个用户(user)拥有几个订单(order),一个订单会被一个用户购买。

现在我们希望查询每个订单的所属情况(订单信息和购买的用户信息)

显然的我们应该在映射文件中配置:

<select id="findAll" resultMap="userMap">select *,o.id oid from user u,orders o where u.id=o.uid
</select>

同时为了展示Order中的user的数据,还需要配置结果集:

<mapper namespace="com.yds.mapper.OrderMapper"><resultMap id="orderMap" type="order"><!--手动指定字段与实体属性的映射关系column:数据表的字段名称property:实体的属性名称--><id column="oid" property="id"/><result column="ordertime" property="ordertime"/><result column="total" property="total"/><result column="uid" property="user.id"/>--><result column="username" property="user.username"/>--><result column="password" property="user.password"/>--><result column="birthday" property="user.birthday"/>--></resultMap>

根据配置,Order的映射接口应该设置如下:

public interface OrderMapper {public List<Order> findAll();}

执行测试方法:

 @Testpublic void test1() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);List<Order> orderList = mapper.findAll();for (Order order : orderList) {System.out.println(order);}sqlSession.commit();sqlSession.close();}

结果如下:

尽管结果相同,但是在映射文件中,这样无法体现user是一个其他的类,所以我们这里引入一个标签association,这个标签可以通过配置property和javaType来直接表示连接对象:

  <!--这里使用association标签,直接表示要通过uid连接对应user中的主键id,并显示user中的各个字段的数据property:当前实体中的属性名称(private User user)javaType:当前实体中的属性的类型(User)--><association property="user" javaType="user"><id column="uid" property="id"/><result column="username" property="username"/><result column="password" property="password"/><result column="birthday" property="birthday"/></association>

2.一对多查询

第二个情景:现在我们想查询每个用户的订单情况

和一对一类似,我们配置映射文件如下:

<mapper namespace="com.yds.mapper.UserMapper"><resultMap id="userMap" type="user"><id column="uid" property="id"/><result column="username" property="username"/><result column="password" property="password"/><result column="birthday" property="birthday"/><!--配置集合信息property:集合名称ofType:当前集合中的数据类型--><collection property="orderList" ofType="order"><!--封装order的数据--><id column="oid" property="id"/><result column="ordertime" property="ordertime"/><result column="total" property="total"/></collection></resultMap><select id="findAll" resultMap="userMap">select *,o.id oid from user u,orders o where u.id=o.uid</select>

这里和一对一唯一不一样的地方在于:因为一个用户有很多订单,所以我们需要获得order的集合orderList,而一对一的情况下,由于一个订单只属于一个用户,所以用户不需要封装成集合。

同时根据配置文件设计一个接口:

public interface UserMapper {public List<User> findAll();}

测试方法如下:

 @Testpublic void test2() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.findAll();for (User user : userList) {System.out.println(user);}sqlSession.commit();sqlSession.close();}

查询结果如下:

3.多对多查询

在先前我们已经创建了user表、role表和user_role中间表了,这里我们直接使用。

多对多的区别在于需要使用中间表来对应两个表中的数据,一个用户可以有多个角色,一个角色也可以有多个用户。

我们配置映射文件如下:

 <resultMap id="userRoleMap" type="user"><!--user的信息--><id column="userId" property="id"/><result column="username" property="username"/><result column="password" property="password"/><result column="birthday" property="birthday"/><!--user内部的roleList信息--><collection property="roleList" ofType="role"><id column="roleId" property="id"/><result column="roleName" property="roleName"/><result column="roleDesc" property="roleDesc"/></collection></resultMap><select id="findUserAndRoleAll" resultMap="userRoleMap">select * from user u,user_role ur,role r where u.id=ur.userId and ur.roleId=r.id;</select>

同时更新user接口:

public interface UserMapper {public List<User> findAll();public List<User> findUserAndRoleAll();}

测试方法:

@Testpublic void test3() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userAndRole = mapper.findUserAndRoleAll();for (User user : userAndRole) {System.out.println(user);}sqlSession.commit();sqlSession.close();}

这里的结果是基于user的(当然也可以基于role,但是就需要再创建一个role的接口和映射文件了):

三、注解开发

我们这里直接沿用上述pojo类和表,这也是我把注解开发和多表操作放一起的原因。

注解开发将映射文件省略,直接将sql语句添加到接口中,实现注解,简化开发。

但是别忘了注解需要被扫描,所以我们在核心配置文件中添加被扫描的包:

<!--加载映射文件(使用注解就不需要了)--><!-- <mappers><mapper resource="com.yds.mapper/UserMapper.xml"/></mappers>--><!--加载映射关系(扫描包)--><mappers><!--指定一个包下的接口--><package name="com.yds.mapper"/></mappers>

1.单表的增删查改

注解可以大幅提升单表的开发效率,这里我们在接口中添加注解:

    @Insert("insert into user values (#{id}, #{username}, #{password}, #{birthday})")public void save(User user);@Update("update user set username=#{username},password=#{password} where id = #{id}")public void update(User user);@Delete("delete from user where id = #{id}")public void delete(int id);@Select("select * from user where id = #{id}")public User findById(int id);@Select("select * from user")public List<User> findAll();

sql语句就直接写在注解中就可以了。

我们这里创建一个测试类来测试增删查改:

public class MyBatisTest {private UserMapper mapper;@Beforepublic void before() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession(true);mapper = sqlSession.getMapper(UserMapper.class);}@Testpublic void testSave(){User user = new User();user.setUsername("yds");user.setPassword("12345");mapper.save(user);}@Testpublic void testUpdate(){User user = new User();user.setId(11);user.setUsername("xzt");user.setPassword("1235");mapper.update(user);}@Testpublic void testDelete(){mapper.delete(11);}@Testpublic void testFindById() {User user = mapper.findById(2);System.out.println(user);}@Testpublic void testFindAll(){List<User> all = mapper.findAll();for (User user : all) {System.out.println(user);}}}

节约时间,我们就直接看看findAll即可:

值得注意的是,这里也使用了@before注解,这是junit单元测试的注解,表示测试方法初始化,在执行每个测试方法前将自动执行注解下的初始化操作,由于我们这些操作的前面几步都是相同的,所以我们只需要放到初始化中执行即可。

2.多表操作

(1)一对一

沿用订单和用户的一对一查询方式

public interface OrderMapper {@Select("select * from orders")@Results({@Result(column = "id",property = "id"),@Result(column = "ordertime",property = "ordertime"),@Result(column = "total",property = "total"),@Result(property = "user",//封装的属性名称column = "uid",//根据哪个字段取查询user表的数据javaType = UserMapper.class,//要封装的 实体类型//select属性 代表查询哪个接口的方法获得数据one = @One(select = "com.yds.mapper.UserMapper.findById"))})/*@Select("select *,o.id oid from orders o,user u where o.uid=u.id")@Results({@Result(column = "oid",property = "id"),@Result(column = "ordertime",property = "ordertime"),@Result(column = "total",property = "total"),@Result(column = "uid",property = "user.id"),@Result(column = "username",property = "user.username"),@Result(column = "password",property = "user.password")})*/public List<Order> findAll();@Select("select * from orders where uid=#{uid}")public List<Order> findByUid(int uid);}

使用results注解来配置对应的字段和外键对应的表的字段。

我们通常使用上面的语法,和标签association一样,可以明确的看到是不同的类。

使用测试类如下:

public class MyBatisMultiTest {private OrderMapper mapper;@Beforepublic void before() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession(true);mapper = sqlSession.getMapper(OrderMapper.class);}@Testpublic void testFindAll(){List<Order> all = mapper.findAll();for (Order order : all) {System.out.println(order);}}
}

效果如下,和xml配置时的一样:

(2)一对多

@Select("select * from user")@Results({@Result(id=true,column = "id",property = "id"),@Result(column = "username",property = "username"),@Result(column = "password",property = "password"),@Result(property = "orderList",column = "id",javaType = List.class,many = @Many(select = "com.yds.mapper.OrderMapper.findByUid"))})public List<User> findUserAndOrderAll();

和xml一样,基于user,这是一对多查询,我们也使用@Result注解配置,最后配置的是order的结果集,由于是对多的配置,所以使用到many的参数,表示查询order表相关数据的方法,因此,我们还需要在OrderMapper中再创建一个查询方法。

@Select("select * from orders where uid=#{uid}")public List<Order> findByUid(int uid);

测试类如下:

public class MyBatisMultiTest2 {private UserMapper mapper;@Beforepublic void before() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession(true);mapper = sqlSession.getMapper(UserMapper.class);}@Testpublic void testFindAll(){List<User> userAndOrderAll = mapper.findUserAndOrderAll();for (User user : userAndOrderAll) {System.out.println(user);}}}

效果如下:

(3)多对多

多对多依旧是需要一个中间表的,由于我们没有使用xml配置,这里我们还需要再创建一个RoleMapper接口来进行配置,我们依旧在注解中使用的是多对多的那条语句。

public interface RoleMapper {@Select("select * from user_role ur,role r where ur.roleId=r.id and ur.userId=#{uid}")public List<Role> findByUid(int uid);}

同时UserMapper接口也需要写:

 @Select("select * from user")@Results({@Result(id = true,column = "id",property = "id"),@Result(id = true,column = "username",property = "username"),@Result(id = true,column = "password",property = "password"),@Result(property = "roleList",column = "id",javaType = List.class,many = @Many(select = "com.yds.mapper.RoleMapper.findByUid"))})public List<User> findUserAndRoleAll();

测试类如下:

public class MyBatisMultiTest3 {private UserMapper mapper;@Beforepublic void before() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession(true);mapper = sqlSession.getMapper(UserMapper.class);}@Testpublic void testFindAll(){List<User> findUserAndRoleAll = mapper.findUserAndRoleAll();for (User user : findUserAndRoleAll) {System.out.println(user);}}}

效果如下:

http://www.dtcms.com/a/427028.html

相关文章:

  • 自动化脚本的自动化执行实践
  • 有颜二维码 1.0.5| 告别单调,一键生成有颜色的二维码
  • 信创浪潮下的国产组态软件——紫金桥RealSCADA
  • 做网站新闻移动动态网络规划设计师资料及视频教程
  • 机器学习之三大学习范式:监督学习、无监督学习、强化学习
  • 18002.机器人电机姿态控制
  • mysql语句基本操作之select查询
  • 做mp3链接的网站宁波专业seo外包
  • Spring Boot 集成 EHCache 缓存解决方案
  • Spring Boot 缓存与验证码生成
  • 进攻------绕后------互换野区
  • Unity 3D笔记(脚本部分)——《B站阿发你好》
  • C++之类的组合
  • 服装购物网站策划书wordpress菜单栏移动下移
  • 【第五章:计算机视觉-项目实战之生成对抗网络实战】1.对抗生成网络原理-(1)对抗生成网络算法基础知识:基本思想、GAN的基本架构、应用场景、标注格式
  • win10软实时设置
  • leetcode 812. 最大三角形面积 简单
  • 机器学习+数字孪生:从诊断到自主决策的跨越
  • 若依前后端分离版学习笔记(十八)——页面权限,页签缓存以及图标,字典,参数的使用
  • 莱芜网站建设哪家好在线logo制作生成免费
  • 哈尔滨网站建设价格网站设计怎么学
  • 再发《管理世界》!智能制造试点DID(2000-2023)
  • SpringCloudGateway:像快递分拣中心一样的API网关
  • 真家宽IP vs 数据中心IP:Cliproxy为何成为跨境电商首选?
  • 声光可调滤光器(AOTF):光谱相机的“电子调谐旋钮”
  • skynet-socket.lua源码分析
  • 悠然无界大模型BLM-1.0:跨空间、跨任务与跨本体泛化的里程碑
  • 安康那个公司做网站好wordpress主题滑动
  • 提升UI走查效率:开发阶段的布局与CSS技巧
  • 5G RedCap模组在智慧城市建设中的应用分析