【MyBatis】基础篇(十四) MyBatis基于注解开发

MyBatis·基础篇(十四) MyBatis基于注解开发


1. mybatis 的常用注解说明

常见注解作用
@Insert实现新增
@Update实现更新
@Delete实现删除
@Select实现查询
@Result实现结果集封装
@Results可以与@Result 一起使用,封装多个结果集
@ResultMap实现引用@Results 定义的封装
@One实现一对一结果集封装
@Many实现一对多结果集封装
@SelectProvider实现动态 SQL 映射
@CacheNamespace实现注解二级缓存的使用

MyBatis中使用注解开发方式,可以减少编写 Mapper 映射文件

2. 使用 Mybatis 注解实现单表操作

2.1 编写实体类

/**
 * @author: LzCc
 * @create: 2019-08-16 17:48
 * @blog: https://blog.youkuaiyun.com/qq_41744145
 * @description: User实体类
 */
public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    //getter、setter...
    //toString...
}

2.2 使用注解方式开发持久层接口

/**
 * @author: LzCc
 * @blog: https://blog.youkuaiyun.com/qq_41744145
 * @description: 基于注解开发的持久层接口
 */
public interface UserMapper {
    /**
     * 查询所有用户
     *
     * @return
     */
    @Select("select * from user")
    List<User> findAll();
    /**
     * 根据 id 查询一个用户
     *
     * @param userId
     * @return
     */
    @Select("select * from user where id = #{uid}")
    User findById(Integer userId);
    /**
     * 保存操作
     *
     * @param user
     * @return
     */
    @Insert("insert into user(username, sex, birthday, address)values(#{username}, #{sex}, #{birthday}, #{address})")
    @SelectKey(keyColumn = "id", keyProperty = "id", resultType = Integer.class, before = false, statement = {"select last_insert_id()"})
    int saveUser(User user);
    /**
     * 更新操作
     *
     * @param user
     * @return
     */
    @Update("update user set username=#{username}, address=#{address}, sex=#{sex}, birthday=#{birthday} where id = #{id}")
    int updateUser(User user);
    /**
     * 删除用户
     *
     * @param userId
     * @return
     */
    @Delete("delete from user where id = #{uid}")
    int deleteUser(Integer userId);
    /**
     * 查询使用聚合函数
     *
     * @return
     */
    @Select("select count(*) from user")
    int findTotal();
    /**
     * 模糊查询
     *
     * @param name
     * @return
     */
    @Select("select * from user where username like #{username}")
    List<User> findByName(String name);
}

@Insert:增加,可以理解为映射文件中的 <insert> 标签
@Select:查询,可以理解为映射文件中的 <select> 标签
@Update:更新,可以理解为映射文件中的 <update> 标签
@Delete:删除,可以理解为映射文件中的 <delete> 标签
@SelectKey:查询逐渐,可以理解为映射文件中的 <selectKey> 标签
* statement :里面写查询主键的 SQL语句
类名:对应了映射文件中的 namespace
方法返回值类型:对应了映射文件中的 resultType

通过注解方式,我们就不需要再去编写 UserMapper.xml 映射文件了!

2.3 编写 SqlMapConfig 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置别名的注册 -->
    <typeAliases>
        <package name="top.lzchao.mybatisquickstart.entity"/>
    </typeAliases>
    <!-- 配置 mybatis 的环境 -->
    <environments default="mysql">
        <!-- 配置 mysql 的环境 -->
        <environment id="mysql">
            <!-- 配置事务的类型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置连接数据库的信息:用的是数据源(连接池) -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 配置映射信息 -->
    <mappers>
        <!-- 配置 dao 接口的位置,它有两种方式
            第一种:使用 mapper 标签配置 class 属性
            第二种:使用 package 标签,直接指定 dao 接口所在的包
            -->
        <package name="top.lzchao.mybatisquickstart.mapper"/>
    </mappers>
</configuration>

2.4 编写测试类,测试方法

/**
 * @author: LzCc
 * @blog: https://blog.youkuaiyun.com/qq_41744145
 * @description: MyBatis注解方式测试
 */
public class MybatisAnnotationTest {
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private UserMapper userMapper;
    @Before
    public void init() throws Exception {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        //3.创建 session
        session = factory.openSession();
        //4.创建代理对象
        userMapper = session.getMapper(UserMapper.class);
    }
    /**
     * 测试查询所有
     */
    @Test
    public void testFindAll() {
        List<User> users = userMapper.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }
    /**
     * 测试查询一个
     */
    @Test
    public void testFindById() {
        User user = userMapper.findById(1);
        System.out.println(user);
    }
    /**
     * 测试保存
     */
    @Test
    public void testSave() {
        User user = new User();
        user.setUsername("mybatis annotation");
        user.setSex("男");
        user.setAddress("俄亥俄克利夫兰");
        user.setBirthday(new Date());
        int res = userMapper.saveUser(user);
        System.out.println("影响数据库记录的行数:" + res);
        System.out.println("插入的主键值:" + user.getId());
    }
    /**
     * 测试更新
     */
    @Test
    public void testUpdate() {
        User user = userMapper.findById(5);
        user.setBirthday(new Date());
        user.setSex("女");
        int res = userMapper.updateUser(user);
        System.out.println(res);
    }
    /**
     * 测试删除
     */
    @Test
    public void testDelete() {
        int res = userMapper.deleteUser(5);
        System.out.println(res);
    }
    /**
     * 测试查询使用聚合函数
     */
    @Test
    public void testFindTotal() {
        int res = userMapper.findTotal();
        System.out.println(res);
    }
    /**
     * 测试模糊查询
     */
    @Test
    public void testFindByName() {
        List<User> users = userMapper.findByName("%杰%");
        for (User user : users) {
            System.out.println(user);
        }
    }
    @After
    public void destroy() throws Exception {
        //提交事务
        session.commit();
        //释放资源
        session.close();
        //关闭流
        in.close();
    }
}

使用注解开发后,基本的CRUD操作变得非常的简单了!

3.使用注解实现复杂关系映射开发

当类中的属性名和查询出来的列名不一致时,当我们要实现复杂关系映射时,我们再映射文件通过 <resultMap> 标签来实现,那么注解开发呢?

3.1 复杂关系映射的注解说明

@Results 注解:

代替的是标签 <resultMap>

该注解中可以使用单个 @Result 注解,也可以使用 @Result 集合
* @Results( { @Result(), @Result() } ) 或 @Results( @Result() )

@Resutl 注解

代替了 <id>标签和 <result>标签

@Result 中 属性介绍:
* id 是否是主键字段
* column 数据库的列名
* property 需要装配的属性名
* one 需要使用的@One 注解 ( @Result( one=@One) ( ) ) )
* many 需要使用的@Many 注解 ( @Result ( many=@many) ( ) ) )

@One 注解(一对一)

代替了标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。

@One 注解属性介绍:

  • select 指定用来多表查询的 sqlmapper
  • fetchType 会覆盖全局的配置参数 lazyLoadingEnabled
  • 使用格式:
    • @Result( column=" “, property=”", one=@One(select = " ") )
@Many 注解(多对一)

代替了标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。

  • 注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义;
  • 使用格式:
    • @Result(property="",column="",many=@Many(select=""))

3.2 使用注解实现一对一复杂关系映射及延迟加载

需求:加载账户信息时并且加载该账户的用户信息,根据情况可实现延迟加载。(注解方式实现)

添加 User 实体类及 Account 实体类
/**
 * @author: LzCc
 * @create: 2019-08-16 17:48
 * @blog: https://blog.youkuaiyun.com/qq_41744145
 * @description: User实体类
 */
public class User implements Serializable {
	private Integer userId;
	private String userName;
	private Date userBirthday;
	private String userSex;
	private String userAddress;
	//getter、setter
	//toString
}
/**
 * @author: LzCc
 * @blog: https://blog.youkuaiyun.com/qq_41744145
 * @description: Account实体类
 */
public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    //多对一关系映射:从表方应该包含一个主表方的对象引用
    private User user;
	//getter、setter
	//toString...
}

注意:User实体类故意将属性名写出与列名不对应

添加账户的持久层接口并使用注解配置
/**
 * @author: LzCc
 * @blog: https://blog.youkuaiyun.com/qq_41744145
 * @description: 账户持久层接口
 */
public interface AccountMapper {
    /**
     * 查询所有账户,采用延迟加载的方式查询账户的所属用户
     * @return
     */
    @Select("select * from account")
    @Results(id = "accountMap",
            value = {
                    @Result(id = true, column = "id", property = "id"),
                    @Result(column = "uid", property = "uid"),
                    @Result(column = "money", property = "money"),
                    @Result(column = "uid",
                            property = "user",
                            one = @One(select = "top.lzchao.mapper.UserMapper.findById", fetchType = FetchType.LAZY)
                    )
            })
    List<Account> findAll();
}

fetchType :

  • lazy :懒加载
  • eager :立即加载
    指定属性后,将在映射中忽略全局配置参数 lazyLoadingEnabled,使用属性的值。
添加用户的持久层接口并使用注解配置
/**
 * @author: LzCc
 * @blog: https://blog.youkuaiyun.com/qq_41744145
 * @description:
 */
public interface UserMapper {
    /**
     * 查询所有用户
     * @return
     */
    @Select("select * from user")
    @Results(id = "userMap",
            value = {
                    @Result(id = true, column = "id", property = "userId"),
                    @Result(column = "username", property = "userName"),
                    @Result(column = "sex", property = "userSex"),
                    @Result(column = "address", property = "userAddress"),
                    @Result(column = "birthday", property = "userBirthday")
            })
    List<User> findAll();
    /**
     * 根据 id 查询一个用户
     * @param userId
     * @return
     */
    @Select("select * from user where id = #{uid} ")
    @ResultMap("userMap")
    User findById(Integer userId);
}
测试一对一关联及延迟加载
@Test
 public void testAccountFindAll() {
     AccountMapper accountMapper = session.getMapper(AccountMapper.class);
     List<Account> accounts = accountMapper.findAll();
     // for(Account account : accounts) {
     // System.out.println(account);
     // System.out.println(account.getUser());
     // }
 }

控制台输出:
在这里插入图片描述
延迟加载已打开

3.3 使用注解实现一对多复杂关系映射

需求:

  • 查询用户信息时,也要查询他的账户列表。使用注解方式实现。

分析:

  • 一个用户具有多个账户信息,所以形成了用户(User)与账户(Account)之间的一对多关系。
User 实体类加入 List
private List<Account> accounts;
public List<Account> getAccounts() {
    return accounts;
}
public void setAccounts(List<Account> accounts) {
    this.accounts = accounts;
}
编写用户的持久层接口并使用注解配置

/**
 * 查询所有用户
 * @return
 */
@Select("select * from user")
@Results(id = "userMap",
        value = {
                @Result(id = true, column = "id", property = "userId"),
                @Result(column = "username", property = "userName"),
                @Result(column = "sex", property = "userSex"),
                @Result(column = "address", property = "userAddress"),
                @Result(column = "birthday", property = "userBirthday"),
                @Result(column = "id", property = "accounts",
                        many = @Many(
                                select = "top.lzchao.mybatisquickstart.mapper.AccountMapper.findByUid",
                                fetchType = FetchType.LAZY
                        )
                )
        })
List<User> findAll();
  • @Many: 相当于 <collection> 的配置
    * select 属性:代表将要执行的 sql 语句
    • fetchType 属性:代表加载方式,一般如果要延迟加载都设置为 LAZY 的值
编写账户的持久层接口并使用注解配置
 /**
  * 根据用户 id 查询用户下的所有账户
  *
  * @param userId
  * @return
  */
@Select("select * from account where uid = #{uid}")
List<Account> findByUid(Integer userId);
添加测试方法
/**
 * 测试查询所有
 */
@Test
public void testFindAll() {
    UserMapper userMapper = session.getMapper(UserMapper.class);
    List<User> users = userMapper.findAll();
    // for(User user : users) {
        // System.out.println("-----每个用户的内容-----");
        // System.out.println(user);
        // System.out.println(user.getAccounts());
    // }
}

控制台输出:
在这里插入图片描述
正常输出

4. MyBatis 基于注解的二级缓存

4.1 在 SqlMapConfig 中开启二级缓存支持

<!-- 配置二级缓存 -->
<settings>
	<!-- 开启二级缓存的支持 -->
	<setting name="cacheEnabled" value="true"/>
</settings>

4.2 在持久层接口中使用注解配置二级缓存

@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface UserMapper {}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值