MyBatis的注解实现复杂映射开发

xml 配置方式实现复杂映射回顾

实现复杂映射我们之前可以在映射文件中通过配置来实现,使用注解开发后,我们可以通过 @Results 注解,@Result 注解,@One 注解和 @Many 注解组合完成复杂关系的配置。

注解说明
@Results
代替的是标签 ,该注解中可以使用单个的 @Result 注解,也可以使用 @Result 集合。
使用方式: @Results({@Result(), @Result()}) 或者 @Results(@Result())
@Result
代替了 标签和 标签
@Result 中的属性介绍
column:数据库中的列名
property:要装配的属性名
one:需要使用 @One 注解( @Result(one=@One)()
many:需要使用 @Many 注解( @Result(many=@many)()
@One(一对一)代替了 标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍
select:指定用来多表查询的 sqlmapper
使用格式: @Result(column="", property="", one=(select=""))
@Many(多对一)代替了 标签,是多表查询的关键,在注解中用来指定子查询返回对象集合。
使用格式: @Result(property="", column="", many=@many(select=""))

一对一查询

一对一查询的模型

用户表和订单表的关系为,一个用户有多个订单,一共订单只属于一个用户

一对一查询需求:查询一个订单,与此同时查询该订单对应的用户

@startuml !include https://unpkg.com/plantuml-style-c4@latest/core.puml ' uncomment the following line and comment the first to use locally '!include core.puml left to right direction class orders { ordertime: varchar(255) total: double uid: int(11) id: int(11) } class user { username: varchar(50) password: varchar(50) birthday: varchar(50) id: int(11) } orders -[#595959,plain]-^ user : "uid:id" @enduml

一对一查询的语句

对应的 sql 语句

select * from orders;
select * from user where id=查询出订单的uid;

查询结果如下:

idordertimetotaluididusernamepasswordbirthday
12019-12-12300011lucy1232019-12-12
22019-12-12400011lucy1232019-12-12
32019-12-12500021lucy1232019-12-12
12019-12-12300012tom1232019-12-12

创建 User 和 Order 实体

/**
 * 订单
 *
 * @name: Order
 * @author: terwer
 * @date: 2022-03-17 17:42
 **/
public class Order {
    private Integer id;
    private String orderTime;
    private Double total;

    // 代表当前订单属于哪一个用户
    private User user;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getOrderTime() {
        return orderTime;
    }

    public void setOrderTime(String 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;
    }

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", orderTime='" + orderTime + '\'' +
                ", total=" + total +
                ", user=" + user +
                '}';
    }
}

/**
 * 用户
 *
 * @name: User
 * @author: terwer
 * @date: 2022-05-25 13:25
 **/
public class User {
    private Integer id;
    private String username;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                '}';
    }
}

创建 IOrderMapper 接口

/**
 * 订单映射
 *
 * @name: IUserMapper
 * @author: terwer
 * @date: 2022-03-17 17:54
 **/
public interface IOrderMapper {
    public List<Order> findOrderAndUser();
}

使用注解配置接口

/**
 * 订单映射
 *
 * @name: IUserMapper
 * @author: terwer
 * @date: 2022-03-17 17:54
 **/
public interface IOrderMapper {
    /**
     * 查询订单同时查询订单所属用户
     *
     * @return
     */
    @Results({
            @Result(property = "id", column = "id"),
            @Result(property = "orderTime", column = "ordertime"),
            @Result(property = "total", column = "total"),
            @Result(property = "user", column = "uid", javaType = User.class, one = @One(select = "com.terwergreen.mapper.IUserMapper.findUserById"))
    })
    @Select("select * from orders")
    public List<Order> findOrderAndUser();
}
/*
 * 用户映射
 *
 * @name: IUserMapper
 * @author: terwer
 * @date: 2022-05-25 13:27
 **/
public interface IUserMapper {
    /**
     * 根据ID查询用户
     * @param id
     * @return
     */
    @Select("select * from user where id=#{id}")
    User findUserById(Integer id);
}

测试结果

/**
 * 订单测试
 *
 * @name: IOrderMapperTest
 * @author: terwer
 * @date: 2022-08-31 22:52
 **/
public class IOrderMapperTest {
    private IOrderMapper orderMapper;
    private SqlSession sqlSession;

    @Before
    public void before() throws Exception {
        System.out.println("before...");
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        sqlSession = sqlSessionFactory.openSession();
        // 这样也是可以的,这样的话后面就不用每次都设置了
        // sqlSession = sqlSessionFactory.openSession(true);
        orderMapper = sqlSession.getMapper(IOrderMapper.class);
    }

    @Test
    public void testFindOrder() throws Exception {
        List<Order> orderAndUser = orderMapper.findOrderAndUser();

        orderAndUser.forEach(order -> {
            System.out.println(order);
        });
    }
}

效果

Opening JDBC Connection
Created connection 2024453272.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@78aab498]
==>  Preparing: select * from orders
==> Parameters: 
<==    Columns: id, ordertime, total, uid
<==        Row: 1, 2019-12-12, 3000.0, 1
====>  Preparing: select * from user where id=?
====> Parameters: 1(Integer)
<====    Columns: id, username, password, birthday
<====        Row: 1, lucy, 123, 2019-12-12
<====      Total: 1
<==        Row: 2, 2019-12-12, 4000.0, 1
<==        Row: 3, 2019-12-12, 5000.0, 2
====>  Preparing: select * from user where id=?
====> Parameters: 2(Integer)
<====    Columns: id, username, password, birthday
<====        Row: 2, tom, 123, 2019-12-12
<====      Total: 1
<==      Total: 3
Order{id=1, orderTime='2019-12-12', total=3000.0, user=User{id=1, username='lucy'}}
Order{id=2, orderTime='2019-12-12', total=4000.0, user=User{id=1, username='lucy'}}
Order{id=3, orderTime='2019-12-12', total=5000.0, user=User{id=2, username='tom'}}

Process finished with exit code 0

调用过程分析

image-20220901002006366

一对多查询

一对多查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户。

一对多查询需求:查询一个用户,与此同时查出该用户具有的订单。

@startuml !include https://unpkg.com/plantuml-style-c4@latest/core.puml ' uncomment the following line and comment the first to use locally '!include core.puml left to right direction class orders { ordertime: varchar(255) total: double uid: int(11) id: int(11) } class user { username: varchar(50) password: varchar(50) birthday: varchar(50) id: int(11) } orders -[#595959,plain]-^ user : "uid:id" @enduml

一对多查询语句

对应查询语句:

对应的 sql 语句

select * from user;
select * from orders where uid=查询出用户的id;

查询结果如下:

idordertimetotaluididusernamepasswordbirthday
12019-12-12300011lucy1232019-12-12
22019-12-12400011lucy1232019-12-12
32019-12-12500021lucy1232019-12-12
12019-12-12300012tom1232019-12-12

修改 User 实体

/**
 * 订单
 *
 * @name: Order
 * @author: terwer
 * @date: 2022-03-17 17:42
 **/
public class Order {
    private Integer id;
    private String orderTime;
    private Double total;

    // 代表当前订单属于哪一个用户
    private User user;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getOrderTime() {
        return orderTime;
    }

    public void setOrderTime(String 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;
    }

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", orderTime='" + orderTime + '\'' +
                ", total=" + total +
                ", user=" + user +
                '}';
    }
}
/**
 * 用户
 *
 * @name: User
 * @author: terwer
 * @date: 2022-05-25 13:25
 **/
public class User {
    private Integer id;
    private String username;

    // 代表当前用户具备那些订单
    private List<Order> orderList;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public List<Order> getOrderList() {
        return orderList;
    }

    public void setOrderList(List<Order> orderList) {
        this.orderList = orderList;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", orderList=" + orderList +
                '}';
    }
}

创建 IUserMapper 接口

/**
 * 用户映射
 *
 * @name: IUserMapper
 * @author: terwer
 * @date: 2022-05-25 13:27
 **/
public interface IUserMapper {
    /**
     * 查询用户和订单
     *
     * @return
     */
    List<User> findUserAndOrder();
}

使用注解配置 Mapper

/**
 * 用户映射
 *
 * @name: IUserMapper
 * @author: terwer
 * @date: 2022-05-25 13:27
 **/
public interface IUserMapper {
    /**
     * 查询用户和订单
     *
     * @return
     */
    @Results({
            @Result(property = "id", column = "id"),
            @Result(property = "username", column = "username"),
            @Result(property = "orderList", column = "id", many = @Many(select = "com.terwergreen.mapper.IOrderMapper.findOrderByUid"), javaType = List.class)
    })
    @Select("select * from user")
    List<User> findUserAndOrder();
}
/**
 * 订单映射
 *
 * @name: IUserMapper
 * @author: terwer
 * @date: 2022-03-17 17:54
 **/
public interface IOrderMapper {
    @Select("select * from orders where uid=#{uid}")
    public List<Order> findOrderByUid(Integer uid);
}

测试结果

public class IUserMapperTest {

    private IUserMapper userMapper;
    private SqlSession sqlSession;

    @Before
    public void before() throws Exception {
        System.out.println("before...");
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        sqlSession = sqlSessionFactory.openSession();
        // 这样也是可以的,这样的话后面就不用每次都设置了
        // sqlSession = sqlSessionFactory.openSession(true);
        userMapper = sqlSession.getMapper(IUserMapper.class);
    }

    @Test
    public void testGetUserOrders() {
        List<User> userAndOrder = userMapper.findUserAndOrder();
        userAndOrder.forEach(user -> {
            System.out.println(user);
        });
    }
}

结果如下:

Opening JDBC Connection
Created connection 98394724.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5dd6264]
==>  Preparing: select * from user
==> Parameters: 
<==    Columns: id, username, password, birthday
<==        Row: 1, lucy, 123, 2019-12-12
====>  Preparing: select * from orders where uid=?
====> Parameters: 1(Integer)
<====    Columns: id, ordertime, total, uid
<====        Row: 1, 2019-12-12, 3000.0, 1
<====        Row: 2, 2019-12-12, 4000.0, 1
<====      Total: 2
<==        Row: 2, tom, 123, 2019-12-12
====>  Preparing: select * from orders where uid=?
====> Parameters: 2(Integer)
<====    Columns: id, ordertime, total, uid
<====        Row: 3, 2019-12-12, 5000.0, 2
<====      Total: 1
<==        Row: 8, 测试2, null, null
====>  Preparing: select * from orders where uid=?
====> Parameters: 8(Integer)
<====      Total: 0
<==        Row: 9, 测试3, null, null
====>  Preparing: select * from orders where uid=?
====> Parameters: 9(Integer)
<====      Total: 0
<==      Total: 4
User{id=1, username='lucy', orderList=[Order{id=1, orderTime='2019-12-12', total=3000.0, user=null}, Order{id=2, orderTime='2019-12-12', total=4000.0, user=null}]}
User{id=2, username='tom', orderList=[Order{id=3, orderTime='2019-12-12', total=5000.0, user=null}]}
User{id=8, username='测试2', orderList=[]}
User{id=9, username='测试3', orderList=[]}

Process finished with exit code 0

多对多查询

多对多查询的模型

用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用。

@startuml !include https://unpkg.com/plantuml-style-c4@latest/core.puml ' uncomment the following line and comment the first to use locally '!include core.puml left to right direction class sys_role { rolename: varchar(255) roleDesc: varchar(255) id: int(11) } class sys_user_role { userid: int(11) roleid: int(11) } class user { username: varchar(50) password: varchar(50) birthday: varchar(50) id: int(11) } sys_user_role -[#595959,plain]-^ sys_role : "roleid:id" sys_user_role -[#595959,plain]-^ user : "userid:id" @enduml

多对多查询需求

查询用户的同时查询该用户对应的角色。

多对多查询的语句

select * from user;
select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=用户的id

查询结果如下:

idrolenameroleDescuseridroleid
1CTOCTO11
2CEOCEO12

代码实现

  • 创建 User 实体和 Role 实体

    /**
     * 用户
     *
     * @name: User
     * @author: terwer
     * @date: 2022-05-25 13:25
     **/
    public class User {
        private Integer id;
        private String username;
    
        // 代表当前用户具备那些订单
        private List<Order> orderList;
    
    
        // 代表当前用户具备的那些角色
        private List<Role> roleList;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public List<Order> getOrderList() {
            return orderList;
        }
    
        public void setOrderList(List<Order> orderList) {
            this.orderList = orderList;
        }
    
        public List<Role> getRoleList() {
            return roleList;
        }
    
        public void setRoleList(List<Role> roleList) {
            this.roleList = roleList;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", orderList=" + orderList +
                    ", roleList=" + roleList +
                    '}';
        }
    }
    
  • 创建 IRoleMapper

    /**
     * 角色映射
     *
     * @name: IRoleMapper
     * @author: terwer
     * @date: 2022-09-06 00:04
     **/
    public interface  IRoleMapper {
        @Select("select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=#{userId}")
        List<Role> findRolesByUserId(Integer userId);
    }
    
    /**
     * 角色
     *
     * @name: Role
     * @author: terwer
     * @date: 2022-05-12 14:14
     **/
    public class Role {
        private Integer id;
        private String rolename;
    
        @Override
        public String toString() {
            return "Role{" +
                    "id=" + id +
                    ", rolename='" + rolename + '\'' +
                    '}';
        }
    }
    
  • 修改 IUserMapper

    /**
     * 用户映射
     *
     * @name: IUserMapper
     * @author: terwer
     * @date: 2022-05-25 13:27
     **/
    public interface IUserMapper {
        @Results({
                @Result(property = "id", column = "id"),
                @Result(property = "username", column = "username"),
                @Result(property = "roleList", column = "id", javaType = List.class,
                        many = @Many(select = "com.terwergreen.mapper.IRoleMapper.findRolesByUserId"))
        })
        @Select("select * from user")
        List<User> findUserAndRole();
    }
    
  • 添加测试方法

    public class IUserMapperTest {
    
        private IUserMapper userMapper;
        private SqlSession sqlSession;
    
        @Before
        public void before() throws Exception {
            System.out.println("before...");
            InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            sqlSession = sqlSessionFactory.openSession();
            // 这样也是可以的,这样的话后面就不用每次都设置了
            // sqlSession = sqlSessionFactory.openSession(true);
            userMapper = sqlSession.getMapper(IUserMapper.class);
        }
    
        @Test
        public void testFindUserAndRole() {
            userMapper.findUserAndRole().forEach(user -> {
                System.out.println(user);
            });
        }
    }
    
  • 效果如下

    Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@51e5fc98]
    ==>  Preparing: select * from user
    ==> Parameters: 
    <==    Columns: id, username, password, birthday
    <==        Row: 1, lucy, 123, 2019-12-12
    ====>  Preparing: select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=?
    ====> Parameters: 1(Integer)
    <====    Columns: id, rolename, roleDesc, userid, roleid
    <====        Row: 1, CTO, CTO, 1, 1
    <====        Row: 2, CEO, CEO, 1, 2
    <====      Total: 2
    <==        Row: 2, tom, 123, 2019-12-12
    ====>  Preparing: select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=?
    ====> Parameters: 2(Integer)
    <====    Columns: id, rolename, roleDesc, userid, roleid
    <====        Row: 1, CTO, CTO, 2, 1
    <====        Row: 2, CEO, CEO, 2, 2
    <====      Total: 2
    <==        Row: 8, 测试2, null, null
    ====>  Preparing: select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=?
    ====> Parameters: 8(Integer)
    <====      Total: 0
    <==        Row: 9, 测试3, null, null
    ====>  Preparing: select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=?
    ====> Parameters: 9(Integer)
    <====      Total: 0
    <==      Total: 4
    User{id=1, username='lucy', orderList=null, roleList=[Role{id=1, rolename='CTO'}, Role{id=2, rolename='CEO'}]}
    User{id=2, username='tom', orderList=null, roleList=[Role{id=1, rolename='CTO'}, Role{id=2, rolename='CEO'}]}
    User{id=8, username='测试2', orderList=null, roleList=[]}
    User{id=9, username='测试3', orderList=null, roleList=[]}
    
    Process finished with exit code 0
    

文章更新历史

2024/05/13 同步文章到其他平台

2022-08-30 feat:初稿

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mybatis是一种基于 Java 的持久层框架,它提供了一种通过注解的方式来进行 SQL 映射的方式,称为 Mybatis 注解映射。使用注解映射可以使得代码更加简洁,也更加易于维护。 在 Mybatis 中,注解主要分为两类:一类是用于描述 SQL 语句的注解,如 @Select、@Insert、@Update、@Delete 等;另一类是用于描述实体类与数据库字段之间映射关系的注解,如 @Results、@Result、@Param 等。 下面是一个使用 Mybatis 注解映射进行 CRUD 操作的示例: 1. 实体类 ```java public class User { private int id; private String name; private int age; //省略getter和setter方法 } ``` 2. Mapper 接口 ```java public interface UserMapper { @Select("SELECT * FROM user WHERE id = #{id}") User getUserById(int id); @Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})") int addUser(User user); @Update("UPDATE user SET name=#{name}, age=#{age} WHERE id=#{id}") int updateUser(User user); @Delete("DELETE FROM user WHERE id=#{id}") int deleteUser(int id); } ``` 3. 配置文件 ```xml <!-- 配置 Mybatis --> <configuration> <!-- 配置 Mapper 接口扫描 --> <mappers> <mapper class="com.example.mapper.UserMapper"/> </mappers> </configuration> ``` 以上代码中,@Select、@Insert、@Update、@Delete 注解分别对应查询、插入、更新、删除操作,其中 #{} 表示占位符,用于接收参数。同时,Mapper 接口中的方法名需要与对应的 SQL 语句名称一致。 除了 SQL 语句的注解外,@Results、@Result、@Param 等注解也可以用于实体类与数据库字段之间的映射关系。例如: ```java @Results(id = "userMap", value = { @Result(property = "id", column = "id", id = true), @Result(property = "name", column = "name"), @Result(property = "age", column = "age") }) public interface UserMapper { @Select("SELECT * FROM user WHERE id = #{id}") @ResultMap("userMap") User getUserById(int id); //省略其他方法 } ``` 以上代码中,@Results 注解用于定义结果集映射规则,@Result 注解用于定义单个属性与字段之间的映射关系,@ResultMap 注解用于引用结果集映射规则。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值