Mybatis之一对多查询注解配置(七)
一、实现步骤
0.创建数据库
- user.table
CREATE TABLE user (
`id` int(11) NOT NULL auto_increment,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime default NULL COMMENT '生日',
`sex` char(1) default NULL COMMENT '性别',
`address` varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ;
- account.table
CREATE TABLE account (
`ID` int(11) NOT NULL COMMENT '编号',
`UID` int(11) default NULL COMMENT '用户编号',
`MONEY` double default NULL COMMENT '金额',
PRIMARY KEY (`ID`),
KEY `FK_Reference_8` (`UID`),
CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ;
1.编写实体类
- User,java
package com.hzxy.domain;
import java.io.Serializable;
import java.util.Date;
/**
* 实现序列化接口
*/
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}';
}
}
- Account.java
package com.hzxy.domain;
import java.io.Serializable;
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//多对一(mybatis中称之为一对一)的映射:一个账户只能属于一个用户
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
2.使用注解方式开发持久层接口
- UserDao.java
package com.hzxy.dao;
import com.hzxy.domain.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
/**
* 用户的持久层接口
*/
public interface UserDao {
/**
* 查询所有用户
* @return
*/
@Select("select * from user")
@Results(id="userMap",value={
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday"),
@Result(property = "accounts",column = "id",
many = @Many(select = "com.hzxy.dao.AccountDao.findAccountByUid",
fetchType = FetchType.LAZY))
})
List<User> findAll();
/**
* 根据id查询用户
* @param userId
* @return
*/
@Select("select * from user where id=#{id} ")
@ResultMap("userMap")
User findById(Integer userId);
}
- AccountDao.java
package com.hzxy.dao;
import com.hzxy.domain.Account;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.mapping.FetchType;
import java.util.List;
public interface AccountDao {
/**
* 查询所有账户,并且获取每个账户所属的用户信息
* @return
*/
@Select("select * from account")
@Results(id="accountMap",value = {
@Result(id=true,column = "id",property = "id"), //true表示主键
@Result(column = "uid",property = "uid"),
@Result(column = "money",property = "money"),
//user封装的类,用uid属性查找
//fetchType:表示加载属性
@Result(property = "user",column = "uid",one=@One(select="com.hzxy.dao.UserDao.findById",fetchType= FetchType.EAGER))
})
List<Account> findAll();
}
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>
<!-- 引入外部配置文件-->
<properties resource="jdbcConfig.properties"></properties>
<!--配置别名-->
<typeAliases>
<package name="com.hzxy.domain"></package>
</typeAliases>
<!-- 配置环境-->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<!-- 指定带有注解的dao接口所在位置 -->
<!-- 配置dao接口的位置,它有两种方式 (注解方式)
第一种:使用mapper标签配置class属性
第二种:使用package标签,直接指定dao接口所在的包
-->
<mappers>
<package name="com.hzxy.dao"></mapper>
</mappers>
</configuration>
4.编写测试方法
package com.hzxy.test;
import com.hzxy.dao.UserDao;
import com.hzxy.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* 测试mybatis的crud操作
*/
public class UserTest {
private InputStream in ;
private SqlSession sqlSession ;
private UserDao userDao ;
@Before //用于在测试方法执行前执行
public void init() throws IOException {
//使用类加载器读取类路径的配置文件,生成字节输入流,不使用绝对路径和相对路径
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory工厂,mybatis使用构建者模式
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//使用工厂生产SqlSession对象
sqlSession = factory.openSession();
//使用SqlSession创建Dao接口的代理对象
userDao = sqlSession.getMapper(UserDao.class);
}
@After //用于在测试方法执行之后执行
public void destroy() throws IOException {
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
in.close();
}
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
for(User user : users){
System.out.println("---每个用户的信息----");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
}
二、相关参数
1.@Results注解
@Results注解 代替的是
<resultMap>
标签
该注解中可以使用单个@Result注解,也可以使用@Result集合 @Results({@Result(),@Result()})或@Results(@Result())
resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。
在 select 标签中使用 resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
2.@Result注解
@Resutl注解 代替的是
<id>
标签和<result>
标签
属性
1.id 是否是主键字段
2.column 数据库的列名
3.property需要装配的属性名
4.one 需要使用的@One注解(@Result(one=@One)()))
5.many 需要使用的@Many注解(@Result(many=@many)()))
id 标签: 用于指定主键字段
column 属性: 用于指定数据库列名
property 属性: 用于指定实体类属性名称
3.One注解
@One注解(一对一)代替的是
<assocation>
标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
属性
select 指定用来多表查询的sqlmapper
fetchType表示加载属性
使用格式: @Result(column=" “,property=”",one=@One(select="",fetchType= FetchType.""))
4.@Many注解
@Many注解(多对一) 代替了
<Collection>
标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意: 聚集元素用来处理“一对多”的关系。需要指定映射的Java实体类的属性,属性的javaType(一般为ArrayList)但是注解中可以不定义。
使用格式: @Result(property="",column="",many=@Many(select=""))
collection: 部分定义了用户关联的账户信息。表示关联查询结果集
property属性 用于指定实体类属性名称
ofType属性" 指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。