对应的四种数据库表关系中存在四种关系:一对多,多对应,一对一,多对多。在前文中已经实现了xml配置方式实现表关系的查询,本文记录一下Mybatis怎么通过注解实现多表的查询,算是一个知识的补充。

  同样的先介绍一下Demo的情况:存在两个实体类用户类和账户类,用户类可能存在多个账户,即一对多的表关系。每个账户只能属于一个用户,即一对一或者多对一关系。我们最后实现两个方法,第一个实现查询所有用户信息并同时查询出每个用户的账户信息,第二个实现查询所有的账户信息并且同时查询出其所属的用户信息。

  1.项目结构

  

  2.领域类

public class Account implements Serializable{
private Integer id;
private Integer uid;
private double money;
private User user; //加入所属用户的属性
省略get 和set 方法.............................
} public class User implements Serializable{
private Integer userId;
private String userName;
private Date userBirthday;
private String userSex;
private String userAddress;
private List<Account> accounts;
省略get 和set 方法.............................
}

  在User中因为一个用户有多个账户所以添加Account的列表,在Account中因为一个账户只能属于一个User,所以添加User的对象。 

  3.Dao层

 public interface AccountDao {
/**
*查询所有账户并同时查询出所属账户信息
*/
@Select("select * from account")
@Results(id = "accountMap",value = {
@Result(id = true,property = "id",column = "id"),
@Result(property = "uid",column = "uid"),
@Result(property = "money",column = "money"),
//配置用户查询的方式 column代表的传入的字段,一对一查询用one select 代表使用的方法的全限定名, fetchType表示查询的方式为立即加载还是懒加载
@Result(property = "user",column = "uid",one = @One(select = "com.example.dao.UserDao.findById",fetchType = FetchType.EAGER))
})
List<Account> findAll(); /**
* 根据用户ID查询所有账户
* @param id
* @return
*/
@Select("select * from account where uid = #{id}")
List<Account> findAccountByUid(Integer id);
} 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 = "birthday",property = "userBirthday"),
@Result(column = "sex",property = "userSex"),
@Result(column = "address",property = "userAddress"),
@Result(column = "id",property = "accounts",many = @Many(select = "com.example.dao.AccountDao.findAccountByUid",fetchType = FetchType.LAZY))
})
List<User> findAll(); /**
* 保存用户
* @param user
*/
@Insert("insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})")
void saveUser(User user); /**
* 更新用户
* @param user
*/
@Update("update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}")
void updateUser(User user); /**
* 删除用户
* @param id
*/
@Delete("delete from user where id=#{id}")
void deleteUser(Integer id); /**
* 查询用户根据ID
* @param id
* @return
*/
@Select("select * from user where id=#{id}")
@ResultMap(value = {"userMap"})
User findById(Integer id); /**
* 根据用户名称查询用户
* @param name
* @return
*/
// @Select("select * from user where username like #{name}")
@Select("select * from user where username like '%${value}%'")
List<User> findByUserName(String name); /**
* 查询用户数量
* @return
*/
@Select("select count(*) from user")
int findTotalUser();

  在findAll()方法中配置@Results的返回值的注解,在@Results注解中使用@Result配置根据用户和账户的关系而添加的属性,User中的属性List<Account>一个用户有多个账户的关系的映射配置:@Result(column = "id",property = "accounts",many = @Many(select = "com.example.dao.AccountDao.findAccountByUid",fetchType = FetchType.LAZY)),使用@Many来向Mybatis表明其一对多的关系,@Many中的select属性对应的AccountDao中的findAccountByUid方法的全限定名,fetchType代表使用立即加载或者延迟加载,因为这里为一对多根据前面的讲解,懒加载的使用方式介绍一对多关系一般使用延迟加载,所以这里配置为LAZY方式。在Account中存在多对一或者一对一关系,所以配置返回值属性时使用:@Result(property = "user",column = "uid",one = @One(select = "com.example.dao.UserDao.findById",fetchType = FetchType.EAGER)),property代表领域类中声明的属性,column代表传入后面select语句中的参数,因为这里为一对一或者说为多对一,所以使用@One注解来描述其关系,EAGER表示使用立即加载的方式,select代表查询本条数据时所用的方法的全限定名,fetchType代表使用立即加载还是延迟加载。

  4.Demo中Mybatis的配置

<?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>
<settings>
<!--&lt;!&ndash;开启全局的懒加载&ndash;&gt;-->
<!--<setting name="lazyLoadingEnabled" value="true"/>-->
<!--&lt;!&ndash;关闭立即加载,其实不用配置,默认为false&ndash;&gt;-->
<!--<setting name="aggressiveLazyLoading" value="false"/>-->
<!--开启Mybatis的sql执行相关信息打印-->
<setting name="logImpl" value="STDOUT_LOGGING" />
<!--<setting name="cacheEnabled" value="true"/>-->
</settings>
<typeAliases>
<typeAlias type="com.example.domain.User" alias="user"/>
<package name="com.example.domain"/>
</typeAliases>
<environments default="test">
<environment id="test">
<!--配置事务-->
<transactionManager type="jdbc"></transactionManager>
<!--配置连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test1"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.example.dao"/>
</mappers>
</configuration>

  主要是记得开启mybatis中sql执行情况的打印,方便我们查看执行情况。

  5.测试

  (1)测试查询用户同时查询出其账户的信息

   测试代码:

public class UserTest {

    private InputStream in;
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
private UserDao userDao;
@Before
public void init()throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
sqlSession = sqlSessionFactory.openSession();
userDao = sqlSession.getMapper(UserDao.class);
}
@After
public void destory()throws Exception{
sqlSession.commit();
sqlSession.close();
in.close();
}
@Test
public void testFindAll(){
List<User> userList = userDao.findAll();
for (User user: userList){
System.out.println("每个用户信息");
System.out.println(user);
System.out.println(user.getAccounts());
}
}

  测试结果:

(2)查询所有账户信息同时查询出其所属的用户信息

  测试代码:

public class AccountTest {

    private InputStream in;
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
private AccountDao accountDao;
@Before
public void init()throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
sqlSession = sqlSessionFactory.openSession();
accountDao = sqlSession.getMapper(AccountDao.class);
}
@After
public void destory()throws Exception{
sqlSession.commit();
sqlSession.close();
in.close();
}
@Test
public void testFindAll(){
List<Account> accountList = accountDao.findAll();
for (Account account: accountList){
System.out.println("查询的每个账户");
System.out.println(account);
System.out.println(account.getUser());
}
}
}

测试结果:

Mybatis基于注解实现多表查询的更多相关文章

  1. Mybatis源码分析--关联表查询及延迟加载原理(二)

    在上一篇博客Mybatis源码分析--关联表查询及延迟加载(一)中我们简单介绍了Mybatis的延迟加载的编程,接下来我们通过分析源码来分析一下Mybatis延迟加载的实现原理. 其实简单来说Myba ...

  2. django之 使用views.py里面的函数对表进行增删改查 内容(models.py中表的创建、views.py中函数的使用,基于对象的跨表查询)

    models之对于表的创建有以下几种: 一对一:ForeignKey("Author",unique=True),  OneToOneField("Author" ...

  3. python 全栈开发,Day73(django多表添加,基于对象的跨表查询)

    昨日内容回顾 多表方案: 如何确定表关系呢? 表关系是在2张表之间建立的,没有超过2个表的情况. 那么相互之间有2条关系线,先来判断一对多的关系. 如果其中一张表的记录能够对应另外一张表的多条记录,那 ...

  4. {django模型层(二)多表操作}一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询

    Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...

  5. 基于对象的跨表查询,多对多查询,多对多操作,聚合查询和分组查询,F查询和Q 查询

    基于对象的跨表查询 一对多查询(班级表和学生表) 表结构创建 class Class(models.Model): id = models.AutoField(primary_key=True) cn ...

  6. Django day08 多表操作 (三) 基于对象的跨表查询 基于双下划线的多表查询

    一: 基于对象的跨表查询 1. 一对一 正向: 反向: 2. 一对多 正向: 反向: 3.多对多 正向: 反向: 4.*****基于对象的多表查询 二: 基于双下划线的多表查询 1. 连表查询 一对一 ...

  7. day61——多表操作(增、删除、改、基于对象的跨表查询)

    day61 增删改查 增加 # 增加 # 一对一 # au_obj = models.AuthorDetail.objects.get(id=4) models.Author.objects.crea ...

  8. 五、Django学习之基于对象的跨表查询

    五.Django学习之基于对象的跨表查询 正向与反向查询 关键在于ForeignKey字段写的位置.例如下面这段代码, 关系属性(字段)写在哪个类(表)里面,从当前类(表)的数据去查询它关联类(表)的 ...

  9. mybatis进阶案例之多表查询

    mybatis进阶案例之多表查询 一.mybatis中表之间的关系 在数据库中,实体型之间的关系主要有如下几种: 1.一对一 如果对于实体集A中的每一个实体,实体集B中至多有一个(也可以没有)实体与之 ...

随机推荐

  1. Oracle导入dump文件

    imp USER/PASSWORD@host/DB_name file=xxx.dmp(path) full=y ignore=y

  2. linux初学者-ftp篇(一)

    linux初学者-ftp篇(一) FTP是文件传输协议,是用于Internet上的控制文件的双向传输.用户可以通过客户机程序从远程主机上下载或者向远程主机上传文件. linux系统中,如果不了解SEL ...

  3. web前端开发-博客目录

    web前端开发是一个新的领域,知识连接范围广,处于设计与后端数据交互的桥梁,并且现在很多web前端相关语言标准,框架库都在高速发展.在学习过程中也常常处于烦躁与迷茫,有时候一直在想如何能够使自己更加系 ...

  4. Android的简述

    程序截图 先来简单了解下程序运行的效果 程序入口点  类似于win32程序里的WinMain函数,Android自然也有它的程序入口点.它通过在AndroidManifest.xml文件中配置来指明, ...

  5. 利用dockerfile 安装一个tomcat7

    FROM docker.io/centos #定义自己的说明 MAINTAINER jim ming "107420988@qq.com" #切换镜像目录,进入/usr/local ...

  6. luogu1373_小a和uim之大逃离 多维dp

    传送门 巧妙之处在于dp的设计只用设计差值即可,因此不会mle,枚举的顺序问题也解决了 #include <bits/stdc++.h> using namespace std; #def ...

  7. 同时启动多个tomcat,端口修改

    所用Tomcat服务器都为zip 版,非安装版.以 tomcat8 为例: 安装第二个Tomcat完成后,打开 tomcat/conf/server.xml 文件,查找以下三处: 1. 修改http访 ...

  8. Spring Cloud微服务接口这么多怎么调试

    导读 我们知道在微服务架构下,软件系统会被拆分成很多个独立运行的服务,而这些服务间需要交互通信,就需要定义各种各样的服务接口.具体来说,在基于Spring Cloud的微服务模式中,各个微服务会基于S ...

  9. Xamarin Android 监听音量键(下)

    上篇在 MainActivity 中重写了按键事件(OnKeyDown),获取了音量键键值并打印了出来,当然,手机物理按键和虚拟按键(音量键.返回键.菜单键等)均可通过该按键事件被捕获. 但是,按键重 ...

  10. 渐进式web应用开发---Service Worker 与页面通信(七)

    _ 阅读目录 一:页面窗口向 service worker 通信 二:service worker 向所有打开的窗口页面通信 三:service worker 向特定的窗口通信 四:学习 Messag ...