Last updated on 十月 11, 2020

这几年来注解开发越来越流行,Mybatis 也可以使用注解开发方式,这样我们就可以减少编写 Mapper 映射文件了。

mybatis 的常用注解说明


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

一、使用 Mybatis 注解实现基本 CRUD

* 用户的持久层接口
 */
public interface IUserDao {

    /**
     * 查询所有用户
     */
    @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 查询一个用户
     */
    @Select("select * from user where id = #{uid} ")
    @ResultMap("userMap")
    User findById(Integer userId);

    /**
     * 保存操作
     *
     * statement属性:填入将会被执行的 SQL 字符串数组。
     * keyProperty属性:填入将会被更新的参数对象的属性的值。
     * before属性:填入 true 或 false 以指明 SQL 语句应被在插入语句的之前还是之后执行。
     * resultType属性:填入 keyProperty 的 Java 类型。
     * statementType属性:填入Statement、 PreparedStatement 和 CallableStatement 中的 STATEMENT、 PREPARED 或 CALLABLE 中任一值填入 。默认值是 PREPARED。
     */
    @Insert("insert into user(username,sex,birthday,address) values " +
            "(#{userName},#{userSex},#{userBirthday},#{userAddress})")
    /*
    如果向数据库中插入一条数据,同时有希望返回该条记录的主键,该怎么处理了?有两种情况:
        (1)数据库主键不是自增列,需要预先生成
        (2)是自增列,插入之后才能获知
     */
    @SelectKey(keyColumn ="id",
            keyProperty = "userId",
            resultType = Integer.class,
            before = false,
            statement = {"select last_insert_id()"})
    int saveUser(User user);

    /**
     * 更新操作
     */
    @Update("update user set username = #{userName},address=#{userAddress}," +
            "sex=#{userSex},birthday=#{userBirthday} " +
            "where id = #{userId} ")
    int updateUser(User user);

    /**
     * 删除用户
     */
    @Delete("delete from user where id = #{userId}")
    int deleteUser(Integer userId);

    /**
     * 聚合函数
     */
    @Select("select count(*) from user")
    int findTotal();

    /**
     * 模糊查询
     */
    @Select("select * from user where username like #{userName}")
     List<User> findByName(String name);


}
//测试类
public class MybatisAnnotationCRUDTest {
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession sqlSession;
    private IUserDao userdao;
    @Before
    public void init() throws IOException {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");

        factory = new SqlSessionFactoryBuilder().build(in);

        sqlSession = factory.openSession();

        userdao = sqlSession.getMapper(IUserDao.class);
    }

    @After
    public void destroy() throws IOException {
        in.close();
    }
    /**
     * 测试查询所有
     */
    @Test
    public void testFindAll(){
        List<User> users = userdao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

    /**
     * 测试查询一个
     */
    @Test
    public void testFindById(){
        User user = userdao.findById(41);
        System.out.println(user);
    }

    /**
     * 测试保存
     */
    @Test
    public void testSave(){
        User user = new User();
        user.setUserName("mybatis annotation");
        user.setUserSex("男");
        user.setUserAddress("北京是顺义区");
        user.setUserBirthday(new Date());
        int res = userdao.saveUser(user);
        System.out.println("影响数据库记录的行数:" + res);
        System.out.println("插入的主键值:" + user.getUserId());
    }

    /**
     * 测试更新
     */
    @Test
    public void testUpdate(){
        User user = userdao.findById(45);
        user.setUserBirthday(new Date());
        user.setUserSex("女");

        int res = userdao.updateUser(user);
        System.out.println(res);

        user = userdao.findById(45);

        sqlSession.commit();
        System.out.println(user);
    }

    /**
     * 测试删除
     */
    @Test
    public void testDelete(){
        int res = userdao.deleteUser(49);
        System.out.println(res);
    }


    /**
     * 测试查询使用聚合函数
     */
    @Test
    public void testFindTotal(){
        int res = userdao.findTotal();
        System.out.println(res);
    }

    /**
     * 测试模糊查询
     */
    @Test
    public void testFindByName(){
        List<User> users = userdao.findByName("%王%");
        for (User user : users) {
            System.out.println(user);
        }
    }

}

注解 复杂结构 分析:

@Results 注解
代替的是标签
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
@Results({@Result(),@Result()})或@Results(@Result())
@Resutl 注解
代替了 标签和标签
@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=""))


一对一 实现!
public interface IUserDao {

    /**
     * 查询所有用户
     */
    @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查询一个用户
     */
    @Select("select * from user where id = #{uid}")
    @ResultMap("userMap")
    User findById(Integer userId);
}
public interface IAccountDao {

    /**
     * 查询所有账户,采用延迟加载的方式,查询账户,所属用户
     */
    /*
    @Result 中 属性介绍:
    id 是否是主键字段
    column 数据库的列名
    property 需要装配的属性名
    one 需要使用的@One 注解(@Result(one=@One)()))
    many 需要使用的@Many 注解(@Result(many=@many)()))
     */
    @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",//user 是account类中的 主表属性
                            one = @One(select = "com.itheima.dao.IUserDao.findById",
                                    fetchType = FetchType.LAZY)
                    )
            })
    /*
    @One 注解(一对一)
    代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
    @One 注解属性介绍:
    select 指定用来多表查询的 sqlmapper
    fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。
    使用格式:
    @Result(column=" ",property="",one=@One(select=""))

     */
    List<Account> findAll();
}

测试类

ublic class AccountTest {
    private IAccountDao accountDao;
    private SqlSession sqlSession;
    private InputStream in;

    @Before
    public void init() throws Exception{
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3.获取SqlSession对象
        sqlSession = factory.openSession(true);
        //4.获取dao的代理对象
        accountDao = sqlSession.getMapper(IAccountDao.class);
    }

    @After
    public void close(){
        sqlSession.close();
    }

    @Test
    public void testFindAll(){
        List<Account> accounts = accountDao.findAll();
//        for (Account account : accounts) {
//            System.out.println(account);
//            System.out.println(account.getUser());
//        }
    }

开启了延迟加载

具体细节 都在代码注释上了!具体自己看!!

一对多实现!

public interface IUserDao {

    /**
     * 查询所有用户
     */
    @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 = "com.itheima.dao.IAccountDao.findByUid",
                                fetchType = FetchType.LAZY
                        )
                )
            })
    /*
    @Many:
    相当于<collection>的配置
    select 属性:代表将要执行的 sql 语句
    fetchType 属性:代表加载方式,一般如果要延迟加载都设置为 LAZY 的值
     */
    List<User> findAll();

    /**
     * 根据id查询一个用户
     */
    @Select("select * from user where id = #{uid}")
    @ResultMap("userMap")
    User findById(Integer userId);
}
public interface IAccountDao {

    /**
     * 根据用户id 查询用户下i的所有账户
     */
    @Select("select * from account where uid = #{uid}")
    List<Account> findByUid(Integer userId);
}
public class AccountTest {
    private IUserDao userDao;
    private SqlSession sqlSession;
    private InputStream in;

    @Before
    public void init() throws Exception{
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3.获取SqlSession对象
        sqlSession = factory.openSession(true);
        //4.获取dao的代理对象
        userDao = sqlSession.getMapper(IUserDao.class);
    }

    @After
    public void close(){
        sqlSession.close();
    }

    @Test
    public void testFindAll(){
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
            System.out.println(user.getAccounts());
        }
    }

最后温馨提示:一定要在 属性类中加入 需要配对的成员变量,不然映射不到的哦