MyBatis 框架

目录

一、概述

1、框架介绍

2、三层架构

3、MyBatis 框架简介

二、IntelliJ IDEA使用MyBatis框架

1、mybatis的环境搭建(查询)

2、基于注解的 MyBatis 框架

3、插入数据

4、更新数据

5、删除数据

6、模糊查询

7、queryVo 查询

三、MyBatis 中的连接池和事务控制

1、Mybatis 连接池的分类

2、Mybatis 中数据源的配置

3、Mybatis 中连接的获取过程分析 

4、Mybatis 的事务控制

四、Mybatis 的动态 SQL 语句

1、 标签

2、 标签

3、 标签

五、Mybatis 多表查询

1、数据准备

2、一对一查询(通过子类方式)

3、一对一查询(通过建立实体类方式) 

4、一对多查询


一、概述

1、框架介绍

框架是我们使用软件开发中的一套解决方案,不同的框架能解决不同的问题,在框架中封装了很多的细节,使开发者可以使用极为简便的方式实现功能,大大的提升了开发的效率。

2、三层架构

  • 表现层:用于展现数据
  • 业务层:用于处理业务需求
  • 持久层:用于和数据库交互

3、MyBatis 框架简介

mybatis是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql语句本身, 而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程,它使用了ORM思想实现了结果集的封装。

ORM:Object Relational Mapping(对象关系映射),即:把数据库表和实体类及实体类的属性对应起来,让开发人员可以操作实体类就可以实现对数据库表的操作

二、IntelliJ IDEA使用MyBatis框架

1、mybatis的环境搭建(查询)

【1】前期准备

在搭建之前先创建了mybatis数据库,并创建了user表,填入 id、username、birthday、sex、address 字段相关的数据

【2】创建 maven 工程

全部创建好后目录结构如下:

从目录结构可以看到:

  • dao包下的IUserDao为dao接口
  • domain下的User类为实体类,是自己根据需求定义的javabean文件
  • resources下的SqlMapConfig.xml为mybatis的主配置文件
  • resources下的com.LSTAR.dao下的IUserDao.xml为映射配置文件
  • 最下面pom.xml为maven工程导入的坐标

【3】导入坐标

在 pom.xml 文件中添加 Mybatis3.4.5 坐标和相关坐标

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.oneStar</groupId>
    <artifactId>oneMybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--导入mybatis的jar包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!--导入SQL相关jar包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>
        <!--导入日志相关jar包-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!--导入测试相关jar包-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</project>

【4】编写 User 实体类

public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUeername() {
        return username;
    }

    public void setUeername(String ueername) {
        this.username = ueername;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", ueername='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

 【5】编写持久层接口 IUserDao

public interface IUserDao {
    /**
     * 查询所有操作
     * @return
     */
    List<User> findAll();
}

 【6】编写持久层接口的映射文件 IUserDao.xml

  • 创建位置:必须和持久层接口在相同的包中
  • 名称:必须以持久层接口名称命名,拓展名为 .xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.LSTAR.dao.IUserDao">
    <!--配置查询所有操作-->
    <select id="findAll">
        select * from user
    </select>
</mapper>

【7】创建 SqlMapConifg.xml 配置文件

<?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">
<!--mybatis的主配置文件-->
<configuration>
    <!--环境配置-->
    <environments default="mysql">
        <!--配置mysql的环境-->
        <environment id="mysql">
            <!--配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据源(连接池)-->
            <dataSource type="POOLED">
                <!--配置数据库连接的四个基本信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
    <mappers>
        <mapper resource="com.LSTAR.dao.IUserDao.xml"/>
    </mappers>
</configuration>

【8】测试类

Mybatis 在测试类中使用的模式:

  • SqlSessionFactory factory = builder.build(in);
    • 构建者模式:把对象的创建细节隐藏,使用者直接调用方法即可拿到对象
  • factory.openSession();
    • 工厂模式:降低了类之间的依赖关系
  • session.getMapper(IUserDao.class);
    • 代理模式:不改变源码的基础上对已有的方法进行增强
public class mybatisTest {
    @Test
    public void Test() throws IOException {
        //1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建 SqlSessionFactory 的构建者对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //3.使用构建者创建工厂对象 SqlSessionFactory
        SqlSessionFactory factory = builder.build(in);
        //4.使用 SqlSessionFactory 生产 SqlSession 对象
        SqlSession session = factory.openSession();
        //5.使用 SqlSession 创建 dao 接口的代理对象
        IUserDao userDao = session.getMapper(IUserDao.class);
        //6.使用代理对象执行查询所有方法
        List<User> users = userDao.findAll();
        for(User user : users) {
            System.out.println(user);
        }
        //7.释放资源   session.close();
        in.close();
    }
}

注意事项

  • 在Mybatis中,会把持久层的操作接口名称和映射文件叫做:Mapper,IUserDao和IUserMapper是一样的
  • 在idea中创建目录的时候,如果要创建多级目录,需要一个一个目录创建,不能com.LSTAR.dao这样创建,否则是一个目录;创建包则可以这样创建
  • Mybatis的映射配置文件位置必须和dao接口的包结构相同
  • 映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
  • 映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名

2、基于注解的 MyBatis 框架

【1】在持久层接口添加注解

@Select("select * from user")

public interface IUserDao {
    /**
     * 查询所有操作
     * @return
     */
    @Select("select * from user")
    List<User> findAll();
}

【2】修改 SqlMapConfig.xml 

告知mybatis映射配置的位置

<!--告知mybatis映射配置的位置-->
<mappers>
    <mapper class="com.LSTAR.dao.IUserDao"/>
</mappers>

进行以上修改后可以将xml的映射配置(IUserDao.xml)给删除

3、插入数据

【1】在持久层接口添加 insertUser 方法

/**
 * 插入数据
 * @param user
 */
void insertUser(User user);

【2】配置映射配置文件

  • parameterType属性:
    • 用于指定传入参数的类型,传入的是一个类的对象,所以写全类名
  • #{ } 字符:
    • 代表占位符,类似 jdbc 中的 ?,用于执行语句时替换实际的数据,由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。它用的是 ognl 表达式
  • ognl 表达式:
    • 它是 apache 提供的一种表达式语言,全称是:Object Graphic Navigation Language  对象图导航语言 
    • 语法格式就是使用  #{对象.对象}的方式 
    • #{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用 getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user. 而直接写 username
<!--插入数据-->
<insert id="insertUser" parameterType="com.LSTAR.domain.User">
    insert into user (username,address,sex,birthday)value(#{username},#{address},#{sex},#{birthday})
</insert>

【3】添加测试方法

public class mybatisTest {
    private InputStream in;
    private SqlSession sqlSession;
    private IUserDao userDao;
    @Before     //用于在测试方法执行之前执行
    public void init() throws IOException {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建 SqlSessionFactory 的构建者对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //3.使用构建者创建工厂对象 SqlSessionFactory
        SqlSessionFactory factory = builder.build(in);
        //4.使用 SqlSessionFactory 生产 SqlSession 对象
        sqlSession = factory.openSession();
        //5.使用 SqlSession 创建 dao 接口的代理对象
        userDao = sqlSession.getMapper(IUserDao.class);
    }
    @After    //用于在测试方法执行之后执行
    public void destory() throws Exception {
        //释放资源   session.close();
        sqlSession.close();
        in.close();
    }

    /**
     * 查询所有数据测试
     * @throws IOException
     */
    @Test
    public void Test() throws IOException {
        //使用代理对象执行查询所有方法
        List<User> users = userDao.findAll();
        for(User user : users) {
            System.out.println(user);
        }
    }

    /**
     * 测试插入数据
     */
    @Test
    public void insertTest() throws IOException {
        User user = new User();
        user.setAddress("袁州区");
        user.setUsername("派大星");
        user.setSex("男");
        user.setBirthday(new Date());
        //使用代理对象执行插入方法
        userDao.insertUser(user);
        sqlSession.commit();
    }
}

4、更新数据

【1】在持久层接口添加 updateUser 方法

/**
 * 更新数据
 * @param user
 */
void updateUser(User user);

【2】配置映射配置文件

<!--更新数据-->
<update id="updateUser" parameterType="com.LSTAR.domain.User">
    update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id}
</update>

【3】添加测试方法

/**
 * 测试更新数据
 */
@Test
public void updateTest() throws IOException {
    User user = new User();
    user.setAddress("湘乡");
    user.setUsername("海绵宝宝");
    user.setSex("女");
    user.setBirthday(new Date());
    user.setId(41);
    //使用代理对象执行更新方法
    userDao.updateUser(user);
    sqlSession.commit();
}

5、删除数据

【1】在持久层接口添加 deleteUser 方法

/**
 * 删除数据
 * @param id
 */
void deleteUser(Integer id);

【2】配置映射配置文件

<!--删除数据-->
<delete id="deleteUser" parameterType="Integer">
    delete from user where id=#{id}
</delete>

【3】添加测试方法

/**
 * 测试删除数据
 */
@Test
public void deleteTest() throws IOException {
    //使用代理对象执行更新方法
    userDao.deleteUser(42);
    sqlSession.commit();
}

6、模糊查询

【1】在持久层接口添加 findByName 方法

/**
 * 模糊查询
 * @param username
 */
List<User> findByName(String username);

【2】配置映射配置文件

  • resultType属性
    • 用于指定结果集的类型
<!--模糊查询-->
<select id="findByName" parameterType="String" resultType="com.LSTAR.domain.User">
    select * from user where username like #{username}
</select>

【3】添加测试方法

/**
 * 模糊查询
 */
@Test
public void findByNameTest() throws IOException {
    //使用代理对象执行查询方法
    List<User> users = userDao.findByName("%星%");
    for(User user : users) {
        System.out.println(user);
    }
}

7、queryVo 查询

【1】创建 QueryVo 类

public class QueryVo implements Serializable {
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

【2】编写持久层接口

/**
 *根据queryVo中的条件查询
 * @param vo
 * @return
 */
List<User> findUserByVo(QueryVo vo);

【3】配置映射配置文件

<!--根据queryVo中的条件查询-->
<select id="findUserByVo" parameterType="com.LSTAR.domain.QueryVo" resultType="com.LSTAR.domain.User">
    select * from user where username like #{user.username}
</select>

【4】添加测试方法

/**
 * 根据queryVo中的条件查询
 */
@Test
public void findUserByVoTest() throws IOException {
    QueryVo vo = new QueryVo();
    User user = new User();
    user.setUsername("%宝%");
    vo.setUser(user);
    //使用代理对象执行查询方法
    List<User> users = userDao.findUserByVo(vo);
    for(User u : users) {
        System.out.println(u);
    }
}

三、MyBatis 中的连接池和事务控制

Mybatis 连接池采用的是自己的连接池技术,在 Mybatis 的 SQLMapConfig.xml 配置文件中,通过 <dataSource type="pooled"> 来实现 Mybatis 中连接池的配置。

1、Mybatis 连接池的分类

 Mybatis 将它自己的数据源 DataSource 分为三类: 

  • UNPOOLED:不使用连接池的数据源
  • POOLED:使用连接池的数据源
  • JNDI:使用 JNDI 实现的数据源

相应地,MyBatis 内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource, PooledDataSource 类来表示 UNPOOLED、POOLED 类型的数据源。 

在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据 库连接,也就是我们所说的连接池技术)。 

2、Mybatis 中数据源的配置

在 SqlMapConfig.xml 文件中,具体配置如下: 

<!--配置数据源(连接池)-->
<dataSource type="POOLED">
    <!-- 配置连接数据库的4个基本信息 -->
    <property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mybatise"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</dataSource>

MyBatis 在初始化时,根据<dataSource>的 type 属性来创建相应类型的的数据源 DataSource,即:

  • type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
  • type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
  • type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用 

3、Mybatis 中连接的获取过程分析 

当我们需要创建 SqlSession 对象并需要执行 SQL 语句时,这时候 MyBatis 才会去调用 dataSource 对象 来创建java.sql.Connection对象。也就是说,java.sql.Connection对象的创建一直延迟到执行SQL语句 的时候。

只有当第 4句sqlSession.selectList("findUserById"),才会触发MyBatis 在底层执行下面这个方 法来创建 java.sql.Connection 对象。

只有在要用到的时候,才去获取并打开连接,当我们用完了就再 立即将数据库连接归还到连接池中。 

@Test 
public void testSql() throws Exception {  
    InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");  
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);  
    SqlSession sqlSession = factory.openSession();  
    List<User> list = sqlSession.selectList("findUserById",41);                  
    System.out.println(list.size()); 
} 

4、Mybatis 的事务控制

Mybatis 框架因为是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC的 setAutoCommit()方法来设置事务提交方式的。 

【1】手动提交事务

/**
 * 测试插入数据
 */
@Test
public void insertTest() throws IOException {
    User user = new User();
    user.setAddress("袁州区");
    user.setUsername("派大星");
    user.setSex("男");
    user.setBirthday(new Date());
    //使用代理对象执行插入方法
    userDao.insertUser(user);
    //手动提交事务
    sqlSession.commit();
}

使用 sqlSession.commit(); 手动提交事务,并且在控制台会有提交事务的打印信息,原因是 setAutoCommit()方法,在执行时它的值被设置为 false 了,所以我们在 CUD 操作中, 必须通过 sqlSession.commit()方法来执行提交操作。

【2】自动提交事务

使用 sqlSession.commit()提交事务,是因为在连接池中取出的连接,都会将调用 connection.setAutoCommit(false)方法,这样我们就必须使用 sqlSession.commit()方法,相当于使用了 JDBC 中的 connection.commit() 方法实现事务提交。

也可以设置自动提交事务,只需在创建 SqlSession 对象时设置参数为 true 即可:

@Before     //用于在测试方法执行之前执行
public void init() throws IOException {
    //1.读取配置文件
    in = Resources.getResourceAsStream("SqlMapConfig.xml");
    //2.创建 SqlSessionFactory 的构建者对象
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    //3.使用构建者创建工厂对象 SqlSessionFactory
    SqlSessionFactory factory = builder.build(in);
    //4.使用 SqlSessionFactory 生产 SqlSession 对象
    sqlSession = factory.openSession(true);
    //5.使用 SqlSession 创建 dao 接口的代理对象
    userDao = sqlSession.getMapper(IUserDao.class);
}

四、Mybatis 的动态 SQL 语句

1、<if> 标签

【1】编写持久层接口

/**
 * 根据条件查询
 * @param user:查询的条件
 * @return
 */
List<User> findByCondition(User user);

【2】持久层映射配置

<!--根据条件查询  if标签-->
<select id="findByCondition" resultType="com.LSTAR.domain.User" parameterType="com.LSTAR.domain.User">
    select * from user where 1=1
    <if test="username != null">
        and username = #{username}
    </if>
</select>

【3】测试类

/**
 * 根据条件查询
 */
@Test
public void findByContion(){
    User u = new User();
    u.setUsername("派大星");
    List<User> users = userDao.findByCondition(u);
    for(User user : users){
        System.out.println(user);
    }
}

2、<where> 标签

在<标签>中, where 1=1 表示的是永远为真,为了简化这个条件封装,可以采用 <where> 标签来进行简化

持久层映射配置

<select id="findByCondition" resultType="com.LSTAR.domain.User" parameterType="com.LSTAR.domain.User">
    select * from user
    <where>
        <if test="username != null">
            and username = #{username}
        </if>
    </where>
</select>

3、<foreach> 标签

  【1】在 QueryVo 中加入一个 List 集合用于封装参数 

public class QueryVo implements Serializable {
    private List<Integer>  ids;

    public List<Integer> getIds() {
        return ids;
    }

    public void setIds(List<Integer> ids) {
        this.ids = ids;
    }
}

【2】持久层映射配置

  • <foreach>:用于遍历集合,属性:
    • collection:代表要遍历的集合元素
    • open:代表语句的开始部分
    • close:代表结束部分
    • item:代表遍历集合的每个元素,生成的变量名
    • sperator:代表分隔符
<!--根据id集合查询用户-->
<select id="findByIds" parameterType="com.LSTAR.domain.QueryVo" resultType="com.LSTAR.domain.User">
    select * from user
    <where>
        <if test="ids != null and ids.size() > 0">
            <foreach collection="ids" open="and id in (" close=")" item="id"  separator=",">
                #{id}
            </foreach>
        </if>
    </where>
</select>

【3】测试类

/**
 * 根据queryVo中的id集合条件查询
 */
@Test
public void findByIdsTest() throws IOException {
    QueryVo vo = new QueryVo();
    List<Integer> list = new ArrayList<Integer>();
    list.add(41);
    list.add(43);
    list.add(49);
    vo.setIds(list);
    //使用代理对象执行查询方法
    List<User> users = userDao.findByIds(vo);
    for(User u : users) {
        System.out.println(u);
    }
}

五、Mybatis 多表查询

1、数据准备

实现多表查询,这里创建两张表,一个是用户表,一个是账户表,使用外键让用户表和账户表之间具备一对多的关系,并建立用户和账户的实体类

【1】创建 mybatise 数据库

创建好数据库后并创建 user 数据表和 account 数据表,并插入相关数据

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`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
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`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

【2】创建实体类

创建用户实体类和账户实体类

public class User implements Serializable{

    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    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 Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
public class Account implements Serializable {

    private Integer id;
    private Integer uid;
    private Double money;

    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 +
                '}';
    }
}

【3】编写持久层接口

public interface IAccountDao {

    /**
     * 查询所有账户,同时还要获取到当前账户的所属用户信息
     * @return
     */
    List<Account> findAll();
}


public interface IUserDao {

    /**
     * 查询所有用户,同时获取到用户下所有账户的信息
     * @return
     */
    List<User> findAll();
}

2、一对一查询(通过子类方式)

eg:现要实现查询所有账户信息,同时还要获取到当前账户的所属用户的用户名和地址信息

【1】定义 AccountUser 类

为了能够封装上面 SQL 语句的查询结果,定义 AccountCustomer 类中要包含账户信息同时还要包含用户信 息,所以我们要在定义 AccountUser 类时可以继承 User 类。 

public class AccountUser extends Account {

    private String username;
    private String address;

    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;
    }

    @Override
    public String toString() {
        return super.toString()+"        AccountUser{" +
                "username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

【2】编写持久层接口

/**
 * 查询所有账户,并且带有用户名称和地址信息
 * @return
 */
List<AccountUser> findAllAccount();

【3】持久层映射配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.dao.IUserDao">
    <!-- 查询所有 -->
    <select id="findAll" resultMap="userAccountMap">
        select a.*,u.username,u.address from account a,user u where a.uid =u.id; 
    </select>
</mapper>

 【4】测试类

/**
 * 测试查询所有账户,同时包含用户名称和地址
 */
@Test
public void testFindAllAccountUser(){
    List<AccountUser> aus = accountDao.findAllAccount();
    for(AccountUser au : aus){
        System.out.println(au);
    }
}

3、一对一查询(通过建立实体类方式) 

通过建立实体类的方式,使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果,所以可以在 Account 类中加入 User 类的对象作为 Account 类的一个属性。

【1】修改 Account 类

在 Account 类中添加以下属性:

//从表实体应该包含一个主表实体的对象引用
private User user;

public User getUser() {
    return user;
}

public void setUser(User user) {
    this.user = user;
}

 【2】修改 AccountDao 接口中的方法

将返回对象改为 Account 类型,因为 Account 类中包含了一个 User 类的对象,它可以封装账户所对应的用户信息

/** 
* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息   
* @return   
*/  
List<Account> findAll(); 

 【3】重新定义 AccountDao.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.dao.IAccountDao">

    <!-- 定义封装account和user的resultMap -->
    <resultMap id="accountUserMap" type="account">
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!-- 一对一的关系映射:配置封装user的内容-->
        <association property="user" column="uid" javaType="user">
            <id property="id" column="id"></id>
            <result column="username" property="username"></result>
            <result column="address" property="address"></result>
            <result column="sex" property="sex"></result>
            <result column="birthday" property="birthday"></result>
        </association>
    </resultMap>

    <!-- 查询所有 -->
    <select id="findAll" resultMap="accountUserMap">
        select u.*,a.id as aid,a.uid,a.money from account a , user u where u.id = a.uid;
    </select>

    <!--查询所有账户同时包含用户名和地址信息-->
    <select id="findAllAccount" resultType="accountuser">
        select a.*,u.username,u.address from account a , user u where u.id = a.uid;
    </select>
</mapper>

【4】测试类

/**
 * 测试查询所有
 */
@Test
public void testFindAll(){
    List<Account> accounts = accountDao.findAll();
    for(Account account : accounts){
        System.out.println("--------每个account的信息------------");
        System.out.println(account);
        System.out.println(account.getUser());
    }
}

4、一对多查询

要实现查询所有用户信息以及用户关联的账户信息,即一对多查询,在查询过程中,如果用户没有账户信息,此时也要将用户信息查询出来,可以使用左外键连接查询。

【1】User类中添加List<Account>

//一对多关系映射:主表实体应该包含从表实体的集合引用
private List<Account> accounts;

public List<Account> getAccounts() {
    return accounts;
}

public void setAccounts(List<Account> accounts) {
    this.accounts = accounts;
}

【2】编写持久层接口

/**
 * 查询所有用户,同时获取到用户下所有账户的信息
 * @return
 */
List<User> findAll();

【3】持久层映射配置

  • collection标签:部分定义了用户关联的账户信息,表示关联查询结果集,属性有:
    • property="accList":关联查询的结果集存储在 User 对象上哪个属性
    • ofType="account":指定关联查询的结果集中的对象类型即 List 中的对象类型,此处可以使用别名,也可以使用全类名
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.dao.IUserDao">

    <!-- 定义User的resultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!-- 配置user对象中accounts集合的映射 -->
        <collection property="accounts" ofType="account">
            <id column="aid" property="id"></id>
            <result column="uid" property="uid"></result>
            <result column="money" property="money"></result>
        </collection>
    </resultMap>

    <!-- 查询所有 -->
    <select id="findAll" resultMap="userAccountMap">
        select * from user u left outer join account a on u.id = a.uid
    </select>

    <!-- 根据id查询用户 -->
    <select id="findById" parameterType="INT" resultType="user">
        select * from user where id = #{uid}
    </select>
</mapper>

【4】测试类

/**
 * 测试查询所有
 */
@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());
    }
}

 


评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ONESTAR博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值