在多表查询中,配置文件的方式更方便些,单表查询中,注解开发会更简单易懂。
看一个注解开发的实例
先定义实体类,并实现其get,set,toString方法,代码略。在定义一个接口,在接口上写注解,如下:
@Select(value = "select * from user")
List<User> findAll();
这样,就配置完了,最后写一个测试文件测试一下即可,测试代码和结果略。
常用的注解如下:
- @Insert:实现新增
- @Update:实现更新
- @Delete:实现删除
- @Select:实现查询
- @Result:实现结果集封装
- @Results:可以与@Result 一起使用,封装多个结果集
- @ResultMap:实现引用@Results 定义的封装
- @One:实现一对一结果集封装
- @Many:实现一对多结果集封装
- @SelectProvider: 实现动态 SQL 映射
当属性名和表中名不一样时,这时查出来结果会全是null。这时我们需要修改一下配置,使查出来结果正常(不修改上面user属性,用一个新的account类)。account类如下:
@Data
public class Account implements Serializable {
private Integer account_id;
private Integer account_uid;
private double account_money;
}
注:我用了@Data标签,这是Lombok插件中的一个注解,其重写了set,get,toString等多种方法。
account表如下:
实体类中的属性名与表中相比,均加了account_
这时,需在IAccountDao中进行额外配置,如下:
@Select("select*from account")
@Results(id = "accountMap",value = {
// 配置主键字段
@Result(id = true,property = "account_id",column ="id" ),
// 配置其他普通字段
@Result(property = "account_uid",column ="uid" ),
@Result(property = "account_money",column ="money" )
})
List<Account> findAll();
在配置主键字段时,有个id=true,表示这个是主键字段。其余属性和我们在xml配置文件中的含义一样。测试文件和测试结果略。
说一下注解中的多表查询情况,这种情况比较麻烦,需要在多个地方进行书写,故只举一对一和一对多的栗子。
就用我们现有的两张表user表和account表,就用户而言,一个用户可以有多个账号,故用户和账号之间的关系是一对多;反过来,一个账户只能被一个用户所拥有,故账户和用户之间的关系是一对一。
一对一:
既然一个账户只能被一个用户所拥有,我们就将结果封装到account中,所以在account中再添加一个属性User user。为了方便起见,把account中的属性名改回来。如下:
@Data
public class Account implements Serializable {
private Integer id;
private Integer uid;
private double money;
private User user;
}
然后,我们现在IAccountDao中进行配置,先上代码:
@Select("select*from account")
@Results(id = "accountMap",value = {
// 配置主键字段 id = true 表示这是主键字段
@Result(id = true,property = "id",column ="id" ),
// 配置其他普通字段
@Result(property = "uid",column ="uid" ),
@Result(property = "money",column ="money" ),
// 配置一对一的关系
@Result(property = "user",column = "uid",one = @One(select = "dao.IUserDao.findById",fetchType = FetchType.EAGER))
})
List<Account> findAll();
这里我们属性名和表中名相同,但不影响我们再配一下,重要的是其中一对一的配置,解释一下一对一中属性名的含义
- property = “user” 多方维护的一方的对象
- column = “uid” 多方表中通过uid这个字段跟一方产生关系
- one 一对一关系的配置
- select = “dao.IUserDao.findById” 查询依据 使用的是用户接口中通过id查询单个用户的这个方法
- fetchType = FetchType.EAGER 加载模式,使用的立即加载
说到加载模式,在多表查询配置中,我们有立即加载和延时加载。一般在一对一中采用立即加载,一对多中采用延时加载。
到这里还没有完,既然我们还要传递id到IUserDao接口中通过id查询单个用户,所以还要去IUserDao中去添加注解,如下:
// 根据id查找用户
@Select("select*from user where id=#{id}")
User findById(Integer id);
到这里,就算实现了。再写一下测试文件即可,我的测试文件和测试结果如下:
@Test
public void testFindAll(){
List<Account> accounts = dao.findAll();
for (Account account : accounts) {
System.out.println(account);
}
}
一对多
既然一个用户可以有多个账户,我们就把结果封装到user里,因此我们需要在User中添加属性:
private List<Account> accounts;
下一步,在IUserDao中写配置文件:
// 查询所有用户
@Select(value = "select * from user")
@Results(id = "userMap",value = {
@Result(id = true,property = "id",column = "id"),
@Result(property = "username",column = "username"),
@Result(property = "password",column = "password"),
@Result(property = "sex",column = "sex"),
@Result(property = "address",column = "address"),
// 配置一对多
@Result(property = "accounts",column = "id",many = @Many(
select = "dao.IAccountDao.findById",
fetchType = FetchType.LAZY
))
})
List<User> findAll();
即便我们属性名和表中字段名相同,也要再写一遍。我们这次使用的是延迟加载
同样,还要去IAccountDao中添加配置文件,如下:
@Select("select*from user where id=#{id}")
Account findById(Integer id);
测试代码和测试结果略。