Mybatis学习第七弹。

Mybatis-7-注解开发

注解开发可以减少xml配置文件的编写。

1. Mybatis中常用的注解

@Insert:新增操作

@Update:更新操作

@Delete:删除操作

@Select:查询操作

@Result:结果集的封装

@Results:与Result一起使用,实现多个结果集封装

@ResultMap:实现引用@Results定义的封装

@One:一对一的结果集封装

@Many:一对多结果集封装

@SelectProvider:动态SQL映射

@CacheNamespace:二级缓存配置

2. 注解开发入门

  1. 根据数据库表封装实体类
  2. 使用注解方式开发持久层接口
  3. 修改SqlMapConfig.xml配置文件
  4. 测试

1. 根据数据库封装实体类

封装User表

1
2
3
4
5
6
7
public class User implements Serializable {
private int id;
private String username;
private Date birthday;
private String sex;
private String address;
}

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

  • 把resources下xml配置文件删除
  • 把SqlMapConfig下的mappers下的Mapper引用改为持久层接口的全限定类名。
  • 使用注解开发
  1. 更改mapper

    1
    2
    3
    <mappers>
    <mapper class="top.tobing.dao.UserDao"></mapper>
    </mappers>
  2. 注解开发

    根据id查询数据

    1
    2
    3
    4
    public interface UserDao {
    @Select("Select * from user where id = #{id}")
    public User findById(int id);
    }

3. 测试

检验注解开发是否能够正常查询出来数据

1
2
3
4
5
@Test
public void findByIdTest(){
User user = userDao.findById(44);
System.out.println(user);
}

结果:User{id=44, username=’CacheTest’, birthday=null, sex=’男’, address=’英国’}

3. 使用注解实现简单CRUD

  1. 使用注解开发实现简单的CRUD
  2. 使用注解配置:数据库列名和实体类属性名的一一对应(非常规)
  1. 创建实体类

    此处故意使得实体类属性名和数据库列名不匹配

    1
    2
    3
    4
    5
    6
    7
    8
    public class User implements Serializable {
    // 对应数据库的列名
    private int userId; // ===>id
    private String userName; // ===>username
    private Date userBirthday; // ===>birthday
    private String userSex; // ===>sex
    private String userAddress; // ===>address
    }
  2. 在UserDao中添加用于对User进行CRUD的抽象方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public interface UserDao {

    // 查询所有用户
    @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")
    })
    public List<User> findAll();

    // 更加Id查询用户
    @Select("Select * from user where id = #{id}")
    @ResultMap("userMap") // 使用userMap封装
    public User findById(Integer id);

    // 保存用户信息
    @Insert("insert into user values(#{userId},#{userName},#{userBirthday},#{userSex},#{userAddress})")
    public int saveUser(User user);

    // 更新用户信息
    @Update("update user set username=#{userName},sex=#{userSex},address=#{userAddress} where id = #{userId}")
    public int updateUser(User user);

    // 查询总记录数
    @Select("Select count(*) from user")
    public int findTotal();

    // 根据用户名模糊查询
    @Select("Select * from user where username like #{username}")
    @ResultMap("userMap") // 使用userMap封装
    public List<User> findByName(String username);
    }
    • 此处由于数据库列名和实体类的字段名不对应,需要通过使用注解@Results和@Result来建立数据库列名和实体类字段名的一一对应关系。
    • 在需要封装结果集的地方使用注解@ResultMap引用自定义的封装。
  3. 测试建议

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    public class UserDaoTest {
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private UserDao userDao;
    @Before
    public void init(){
    try {
    //1.读取配置文件
    in = Resources.getResourceAsStream("SqlMapConfig.xml");
    //2.创建工厂类
    factory =new SqlSessionFactoryBuilder().build(in);
    //3.生产SqlSession对象
    session = factory.openSession();
    //4.获取代理对象
    userDao = session.getMapper(UserDao.class);
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    @After
    public void destory() throws IOException {
    session.commit();
    session.close();
    in.close();
    }
    @Test
    public void findByIdTest(){
    User user = userDao.findById(44);
    System.out.println(user);
    }

    // 查询所有用户
    @Test
    public void findAllTest() {
    List<User> users = userDao.findAll();
    for (User user : users) {
    System.out.println(user);
    }
    }

    // 保存用户信息
    @Test
    public void saveUser() {
    User u = new User();
    u.setUserAddress("水帘洞");
    u.setUserBirthday(new Date());
    u.setUserName("孙悟空");
    u.setUserSex("男");
    int res = userDao.saveUser(u);
    System.out.println(res);
    }

    // 更新用户信息
    @Test
    public void updateUser(){
    User u = new User();
    u.setUserName("孙悟饭");
    u.setUserAddress("水帘洞");
    u.setUserBirthday(new Date());
    u.setUserSex("男");
    u.setUserId(47);
    int res = userDao.updateUser(u);
    System.out.println(res);
    }

    // 查询总记录数
    @Test
    public void findTotal(){
    int total = userDao.findTotal();
    System.out.println(total);
    }

    // 根据用户名模糊查询
    @Test
    public void findByName(){
    List<User> users = userDao.findByName("%张%");
    for (User user : users) {
    System.out.println(user);
    }
    }
    }

4. 使用注解查询复杂关系

1. 注解说明

1
2
3
4
5
@Results(id = '' value = {
@Result(),
@Result(),
...
})
  1. Results

    1
    2
    3
    4
    public @interface Results {
    String id() default ""; // 指定主键
    Result[] value() default {}; // 指定类名和属性的对应关系(Result注解)
    }
  2. Result

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public @interface Result {
    boolean id() default false; // 是否为主键

    String column() default ""; // 数据库列名

    String property() default ""; // 实体类属性名

    One one() default @One; // 使用@One注解

    Many many() default @Many; // 使用@Many注解
    }
  3. One

    1
    2
    3
    4
    5
    public @interface One {
    String select() default ""; // 指定用于多表查询的sqlMapper
    // 覆盖全局的配置参数lazyLoadingEnable
    FetchType fetchType() default FetchType.DEFAULT;
    }
  4. Many

    1
    2
    3
    4
    5
    public @interface Many {
    String select() default ""; // 指定用于多表查询的sqlMapper
    FetchType fetchType() default FetchType.DEFAULT;

    }
  5. 总结

    • @One

      • 指定一对一

      • 代替了<assocation>标签,是多表查询的关键。

      • 用于指定查询返回单一对象

    • @Many

      • 指定一对多
      • 代替了<Collection>,是多表查询的关键
      • 用于指定查询返回集合对象

2. 使用注解开发一对一的复制关系映射

需求:加载账号时,加载用户信息。(可根据情况延迟加载)

  1. 创建Account类和User类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // Account类
    public class Account implements Serializable {
    private int id;
    private int uid;
    private double money;
    private User user; // 与账号一一对应的用户
    }
    // User类
    public class User implements Serializable {
    private int userId;
    private String userName;
    private Date userBirthday;
    private String userSex;
    private String userAddress;
    private List<Account> accounts;
    }
  1. 添加Account持久层dao并使用注解配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public interface AccountDao {
    @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.tobing.dao.UserDao.findById",// 调用UserDao.findById实现延迟查询
    fetchType= FetchType.LAZY) // 延迟加载
    )
    })
    List<Account> findAll(); // 查询所有方法
    }

  1. 添加User持久层dao并使用注解配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public interface UserDao {

    // 查询所有用户
    @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")
    })
    public List<User> findAll();

    // 更加Id查询用户
    @Select("Select * from user where id = #{id}")
    @ResultMap("userMap") // 使用userMap封装
    public User findById(Integer id);
    }
  1. 测试数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Test
    public void findAllTest(){
    List<Account> accounts = accountDao.findAll();
    for (Account account : accounts) {
    System.out.println("-------------------------");
    System.out.println(account);
    System.out.println(account.getUser());
    }
    }
  1. 测试延迟加载

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Test
    public void lazyLoadingTest(){
    List<Account> accounts = accountDao.findAll();
    for (Account account : accounts) {
    System.out.println(account.getMoney());
    System.out.println(account.getId());
    }
    }

3. 使用注解开发一对多的复杂关系映射

需求:查询用户信息,按需查询其账号信息。(延迟加载)

  1. User中加入List<Account>

  2. 编写User持久层接口并使用注解配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public interface UserDao {

    // 查询所有用户
    @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.tobing.dao.AccountDao.findByUid",
    fetchType = FetchType.LAZY
    ))
    })
    public List<User> findAll();
    }
  1. 编写Account持久层接口并使用注解配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public interface AccountDao {

    @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.tobing.dao.UserDao.findById",
    fetchType= FetchType.LAZY)
    )
    })
    List<Account> findAll();

    @Select("select * from account where uid = #{uid}")
    @ResultMap("accountMap")
    List<Account> findByUid();
    }

  1. 添加测试方法

    1
    2
    3
    4
    5
    6
    7
    @Test
    public void findAllTest() {
    List<User> users = userDao.findAll();
    for (User user : users) {
    System.out.println(user.getUserName());
    }
    }

5. 注解实现开启二级缓存

1. SqlMapConfig配置

1
2
3
4
5
6
<configuration >
<settings>
<setting name="cacheEnable" value="true"/>
</settings>
......
</configuration>

2. 持久层注解开启二级缓存

1
2
3
4
@CacheNamespace(blocking =true)
public interface UserDao {
.....
}

评论