[Spring+SpringMVC+Mybatis]框架学习笔记(九):Mybatis主配置文件和映射文件

第9章 Mybatis主配置文件和映射文件

ZXQOgI.png

9.1 用Mybatis进行开发的两种方式

在正式的开发环境中用Mybatis进行开发有两种方式:

1)原始的接口和实现类的方式
缺点:

  • 重复代码太多,sqlSession的操作
  • statement的id硬编码将来影响维护

2)基于mapper代理的开发方式(重点)
mybatis根据一些规则自动创建dao接口的实现类的代理对象
规则:

  • userMapper.xml中namespace必须指定为UserMapper(相当于第8讲案例中的IUserDao)的全限定类名
  • userMapper.xml中statement(即sql语句)的id指定为UserMapper接口中对应的方法名称
  • userMapper.xml中statement的输入参数类型和UserMapper中对应的方法参数类型一致
  • userMapper.xml中statement的返回类型和UserMapper中的对应方法的返回类型一致

9.2 主配置文件config.xml详解

* properties标签
    主要用于配置数据库的连接数据
* settings  全局的配置参数
    mybatis中的运行时行为设置 ,比如缓存的开启,驼峰命名的映射,延迟加载的设置等等 
* plugins
    mybatis需要引入的一些插件 :分页插件pageHelper            
* enviroments
    环境配置,可以配置多种数据库连接
* mapper
    详见mybatis-config.xml

9.3 映射文件mapper.xml详解

  • 输入参数parameterType
    • 简单类型的单个参数
      需求:根据用户id查询用户信息
    • 简单类型的多个参数
      需求:通过登录名和密码验证用户是否存在
    • 包装类对象作为输入参数进行查询
      需求:根据界面输入的用户名称或者登录名称来查询符合条件的用户列表
  • 动态sql
    • if标签和where标签
    • sql片段
    • foreach
  • 输出参数resultType/resultMap
    • 简单类型的输出 Integer(可写为int,即用别名,该别名是自动设置的,不需要在主配置文件中设置) String Long(可写为long)
    • 对象的输出
    • HashMap的输出
    • resultMap对象输出(当数据库设计时没有遵循命名规则,java设计也没有遵循命名规则时使用 --> 手动设置数据库表列名与java属性之间的对应关系)

9.4 基于mapper代理的Mybatis的Demo

ZXlK54.png

9.4.1 测试数据准备

ZX3TET.png

ZX37UU.png

jdbc的属性配置文件:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis_test
jdbc.user=root
jdbc.password=123

9.4.2 User实体类、Dao接口

User实体类与8.4.2相同。

包装类UserDto:

package com.steven.mybatis.sysmanage.dto;

import com.steven.mybatis.sysmanage.entity.User;

/**
 * 跟数据库M_USER表对应的实体类
 * @author chenyang
 *
 */
public class UserDto implements java.io.Serializable{

    private static final long serialVersionUID = 1L;
    
    private User user;
    
    public User getUser(){
        return user;
    }
    
    public void setUser(User user){
        this.user = user;
    }
}

Dao接口UserMapper基本与8.4.2相同,这里增加了几个方法。

package com.steven.mybatis.sysmanage.mapper;

import java.util.List;
import java.util.Map;

import com.steven.mybatis.sysmanage.dto.UserDto;
import com.steven.mybatis.sysmanage.entity.User;

/**
 * 定义用户增删改查dao接口
 * @author chenyang
 *
 */
public interface UserMapper {
    /**
     * 根据用户id获取用户对象信息
     * @param userId
     * @return
     */
    public User getUserById(Long userId);
    /**
     * 通过登录名和密码来验证用户是否存在
     * @param loginName
     * @param password
     * @return
     */
    public User getUserByLoginNameAndPsd(String loginName, String password);
    /**
     * 通过用户实体包装类来进行查询
     * @param userDto
     * @return
     */
    public List<User> getUserListByUserDto(UserDto userDto);
    /**
     * 获取所有用户数目
     * @return
     */
    public Integer getUserCount();
    /**
     * 查询所有用户数据,以map结构数据返回
     * @return
     */
    public List<Map<Object, Object>> getUserListMap();
    /**
     * 查询所有用户数据,用resultMap返回结果集
     * @return
     */
    public List<User> getUserListByResultMap();
    /**
     * 查询所有用户数据,查询所有用户对象
     * @return
     */
    public List<User> getUserList();
    
    /**
     * 增加用户对象
     * @param user
     */
    public void addUser(User user);
    /**
     * 删除用户对象
     * @param user
     */
    public void delUser(User user);
    /**
     * 修改用户对象
     * @param user
     */
    public void updateUser(User user);
    
}

9.4.3 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>
    <properties resource="jdbc.properties"></properties>
    
    <settings>
    <!-- 是否开启自动检测驼峰命名规则,如USER_ID userId
        即从经典的数据表列名AB_COLUMN到经典的java属性名的映射abColumn
        默认是false
     -->
        <setting name="mapUnderscoreToCamelCase" value="true"></setting>
    </settings>
    
    <!-- 设置别名 -->
    <typeAliases>
        <!-- 单个设置别名 -->
        <!-- <typeAlias type="com.steven.mybatis.sysmanage.entity.User" alias="user"/> -->
        <!-- 批量设置别名 -->
        <package name="com.steven.mybatis.sysmanage.entity"/>
    </typeAliases>

    <!-- 默认引用那个数据库环境 -->    
    <environments default="defaultEnv">
        <environment id="defaultEnv">
            <!-- 事务管理方式 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 数据库连接四要素 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    
    <!-- 加入所有的sql映射文件 -->
    <mappers>
        <!-- 第一种方式,用resource属性,注意目录用/分隔 -->
        <!-- <mapper resource="com/steven/mybatis/sysmanage/mapper/UserMapper.xml"></mapper> -->
        <!-- 第二种方式,用class属性应用接口类,规则:接口类和sql映射文件必须同名,然后在同一路径 -->
        <!-- <mapper class="com.steven.mybatis.sysmanage.mapper.UserMapper"></mapper> -->
        <!-- 第三种方式,用package标签批量自动扫描所配置的包路径的所有接口
               规则:接口类和sql映射文件必须同名,然后在同一路径-->
        <package name="com.steven.mybatis.sysmanage.mapper"></package>
    </mappers>
</configuration>

9.4.4 对象映射文件

<?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.steven.mybatis.sysmanage.mapper.UserMapper">
     <select id="getUserById" parameterType="long" resultType="user">
        SELECT USER_ID,USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE FROM M_USER 
        WHERE USER_ID=#{ID}
     </select>
     <!-- 通过登录名和密码验证用户是否存在 -->
     <select id="getUserByLoginNameAndPsd" resultType="user">
        SELECT USER_ID,USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE FROM M_USER 
        WHERE LOGIN_NAME=#{0} AND PASSWORD=#{1}
     </select>
     
     <!-- 通过包装类UserDto的条件来查询用户列表-->
     <!-- 当我们根据过滤条件查询时,如果需要用到模糊查询,我们不能用占位符#{},
              得用${}拼接将查询的sql和参数拼接起来
              注意:拼接符容易引起sql注入和sql执行效率问题,慎用!
              能用占位符就不用拼接符
      -->
     <select id="getUserListByUserDto" parameterType="com.steven.mybatis.sysmanage.dto.UserDto" resultType="user">
        SELECT USER_ID,USER_NAME,LOGIN_NAME,PASSWORD,DEPT_ID,BIRTHDAY,TV_UPDATE FROM M_USER
        <!-- where标签有两个用途:1:添加sql的where关键字;2:判断第一个条件不需要and -->
        <where>
            <if test="user!=null">
                <if test="user.loginName!=null">AND LOGIN_NAME LIKE '%${user.loginName}%'</if>
                <if test="user.userName!=null">AND USER_NAME LIKE '%${user.userName}%'</if>
                <if test="user.birthday!=null">AND BIRTHDAY=#{user.birthday}</if>
                <if test="user.deptId!=null">AND DEPT_ID=#{user.deptId}</if>
            </if>
        </where>
     </select>
     
     <!-- 查询用户数目 -->
     <select id="getUserCount" resultType="int">
        SELECT COUNT(0) FROM M_USER
     </select>
     
     <!-- 查询所有用户信息 -->
     <select id="getUserList" resultType="user">
        SELECT USER_ID,USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE FROM M_USER
     </select>
     
     <!-- 查询所有用户信息,用map返回-resultType -->
     <select id="getUserListMap" resultType="hashMap">
        SELECT USER_ID,USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE FROM M_USER
     </select>
     
     <!-- 定义一个resultMap id="userResultMap" -->
     <resultMap type="user" id="userResultMap">
        <!-- id标签代表数据库的主键;column代表列名或者sql中的别名;property代表java对象的属性名 -->
        <!-- 当数据库字段名和java类属性名遵循了命名规则时,下面的对应关系可以省略不用写 -->
        <id column="ID" property="userId"></id>
        <result column="USER_NAME" property="userName"></result>
        <result column="LOGIN_NAME" property="loginName"></result>
        <result column="BIRTHDAY" property="birthday"></result>
        <result column="TV_UPDATE" property="tvUpdate"></result>
     </resultMap>
     
     <!-- 查询所有用户信息,以resultMap方式返回 -->
     <select id="getUserListByResultMap" resultMap="userResultMap">
        SELECT USER_ID,USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE FROM M_USER
     </select>

     <!-- 增加用户记录 -->
     <insert id="addUser" parameterType="user">
        INSERT INTO M_USER(USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE)
        VALUES(#{userName},#{loginName},#{birthday},#{tvUpdate})
     </insert>
     
     <!-- 删除用户 -->
     <delete id="delUser" parameterType="user">
        DELETE FROM M_USER WHERE USER_ID=#{userId}
     </delete>
     
     <!-- 修改用户 -->
     <update id="updateUser" parameterType="user">
        UPDATE M_USER SET USER_NAME=#{userName},LOGIN_NAME=#{loginName},
        BIRTHDAY=#{birthday} WHERE USER_ID=#{userId}
     </update>
</mapper>

9.4.5 测试

package com.steven.mybatis.sysmanage.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

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.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;

import com.steven.mybatis.sysmanage.dto.UserDto;
import com.steven.mybatis.sysmanage.entity.User;
import com.steven.mybatis.sysmanage.mapper.UserMapper;

public class MyBatisMapperTest {
    static Logger log = Logger.getLogger(MyBatisMapperTest.class);
    
    private SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    
    @Before
    public void init() throws IOException{
        String configFile = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(configFile);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        sqlSession = sqlSessionFactory.openSession();
    }
    
    //根据用户id查询用户,明细信息
    @Test
    public void testGetUserById(){
        //在用mapper代理方式进行开发的时候,通过sqlSession.getMapper获取接口的实现类
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        log.info(userMapper.getUserById(1L));
    }
    
    //根据用户名和密码验证用户是否存在
    @Test
    public void testGetUserByLoginNameAndPsw(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        log.info(userMapper.getUserByLoginNameAndPsd("lilei", "abc"));
    }
    
    //根据UserDto对象验证用户是否存在
    @Test
    public void testGetUserListByUserDto(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        UserDto userDto = new UserDto();
//      User user = new User();
//      user.setLoginName("Steven");
//      userDto.setUser(user);  如果不设置属性,就返回全部
        log.info(userMapper.getUserListByUserDto(userDto));
    }
    
    //查询用户总数
    @Test
    public void testGetUserCount(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        log.info(userMapper.getUserCount());
    }
    
    //查询所有用户:
    //方式一:测试返回结果为User的对象格式
    @Test
    public void testGetUserList(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();
        log.info(userList);
    }
    
    
    //方式二:测试返回结果为hashmap的对象格式
    @Test
    public void testGetUserListMap(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<Map<Object,Object>> userListMap = userMapper.getUserListMap();
        log.info(userListMap);
    }
    
    //方式三:测试resultMap的返回结果
    @Test
    public void testGetUserListByResultMap(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserListByResultMap();
        log.info(userList);
    }
    
    //增、删、改省略
    
}

查询所有用户三种方式结果对比:

方式一:getUserList
[User [userId=1, userName=chenyang, loginName=Steven, password=null, deptId=null, birthday=1986-09-18 00:00:00.0, tvUpdate=2018-02-28 00:00:00.0], User [userId=2, userName=lilei, loginName=lilei, password=null, deptId=null, birthday=1989-09-10 00:00:00.0, tvUpdate=2018-02-28 00:00:00.0], User [userId=4, userName=zhangsan, loginName=Jerry, password=null, deptId=null, birthday=1990-10-03 00:00:00.0, tvUpdate=2018-02-28 00:00:00.0]]

方式二:getUserListMap(它是根据sql语句中要select的字段来显示,sql中没有PASSWORD和DEPT_ID,所有结果中也没有这两个结果)
[{USER_ID=1, TV_UPDATE=2018-02-28 00:00:00.0, USER_NAME=chenyang, LOGIN_NAME=Steven, BIRTHDAY=1986-09-18 00:00:00.0}, {USER_ID=2, TV_UPDATE=2018-02-28 00:00:00.0, USER_NAME=lilei, LOGIN_NAME=lilei, BIRTHDAY=1989-09-10 00:00:00.0}, {USER_ID=4, TV_UPDATE=2018-02-28 00:00:00.0, USER_NAME=zhangsan, LOGIN_NAME=Jerry, BIRTHDAY=1990-10-03 00:00:00.0}]

方式三:getUserListByResultMap(第一种方式与第三种方式返回结果一致)
[User [userId=1, userName=chenyang, loginName=Steven, password=null, deptId=null, birthday=1986-09-18 00:00:00.0, tvUpdate=2018-02-28 00:00:00.0], User [userId=2, userName=lilei, loginName=lilei, password=null, deptId=null, birthday=1989-09-10 00:00:00.0, tvUpdate=2018-02-28 00:00:00.0], User [userId=4, userName=zhangsan, loginName=Jerry, password=null, deptId=null, birthday=1990-10-03 00:00:00.0, tvUpdate=2018-02-28 00:00:00.0]]

9.5 动态sql

  • if标签和where标签
    例见9.4.
  • foreach
    需求:需要查询指定id集合的所有用户信息
    SELECT * FROM M_USER WHERE USER_ID IN (1,2,3)
  • sql片段
    将通用的sql语句提取出来,称为sql片段,给不同方法应用
  • 增加记录返回主键
    <!--以oracle数据库为例,需要调用序列  -->
    <!-- <selectKey keyProperty="userId" resultType="long" order="BEFORE">
        SELECT IDSEQUENCE.NEXTVAL FROM DUAL
    </selectKey>
    INSERT INTO M_USER(USER_ID,USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE)
    VALUES(#{userId},#{userName},#{loginName},#{birthday},#{tvUpdate}) -->
    
    <!-- 以mysql为例 -->
    <selectKey keyProperty="userId" resultType="long" order="AFTER">
        SELECT LAST_INSERT_ID() AS userId
    </selectKey>
    INSERT INTO M_USER(USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE)
    VALUES(#{userName},#{loginName},#{birthday},#{tvUpdate})
  1. 在UserDto包装类中增加ids属性
package com.steven.mybatis.sysmanage.dto;

import java.util.List;

import com.steven.mybatis.sysmanage.entity.User;

/**
 * 跟数据库M_USER表对应的实体类
 * @author chenyang
 *
 */
public class UserDto implements java.io.Serializable{

    private static final long serialVersionUID = 1L;
    
    private User user;
    
    private List<Long> ids;
    
    public User getUser(){
        return user;
    }
    
    public void setUser(User user){
        this.user = user;
    }

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

    public void setIds(List<Long> ids) {
        this.ids = ids;
    }
    
}
  1. mapper文件
<?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.steven.mybatis.sysmanage.mapper.UserMapper">
    <select id="getUserListByUserDto" parameterType="com.steven.mybatis.sysmanage.dto.UserDto" resultType="user">
        SELECT
        <include refid="user_column"></include>
        FROM M_USER
        <!-- where标签有两个用途:1:添加sql的where关键字;2:判断第一个条件不需要and -->
        <where>
            <include refid="query_user_sql_where"></include>            
        </where>
    </select>
    
    <!--将通用的sql语句提取出来,称为sql片段,给不同方法复用  -->
    <sql id="query_user_sql_where">
        <if test="user!=null">
                <if test="user.loginName!=null">AND LOGIN_NAME LIKE '%${user.loginName}%'</if>
                <if test="user.userName!=null">AND USER_NAME LIKE '%${user.userName}%'</if>
                <if test="user.birthday!=null">AND BIRTHDAY=#{user.birthday}</if>
                <if test="user.deptId!=null">AND DEPT_ID=#{user.deptId}</if>
            </if>
            
        <!-- 需求:实现sql的where部分: AND  USER_ID IN(1,2,3) -->
        <if test="ids!=null">
            <!-- collection:输入参数的属性;open:循环前的开始符合;close:循环后的结束符合 -->
            <foreach collection="ids" open="AND USER_ID IN(" close=")" item="id" separator=",">
                #{id}
            </foreach>          
        </if>
    </sql>
    
    <!-- slq语句中的列名也可以复用 -->
    <sql id="user_column">USER_ID,USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE</sql>
    <sql id="user_column_with_alisas">A.USER_ID,A.USER_NAME,A.LOGIN_NAME,A.BIRTHDAY,A.TV_UPDATE</sql>
    
    <insert id="addUser" parameterType="user">
        <!-- 以mysql为例,由于mysql中可以用到自增长,USER_ID是自增长,需求:返回userId值 -->
        <selectKey keyProperty="userId" resultType="long" order="AFTER">
            SELECT LAST_INSERT_ID() AS userId
        </selectKey>
        INSERT INTO M_USER(USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE)
        VALUES(#{userName},#{loginName},#{birthday},#{tvUpdate})
        
        <!--以oracle数据库为例,没有自增长,需要调用序列  -->
        <!-- <selectKey keyProperty="userId" resultType="long" order="BEFORE">
            SELECT IDSEQUENCE.NEXTVAL FROM DUAL
        </selectKey>
        INSERT INTO M_USER(USER_ID,USER_NAME,LOGIN_NAME,BIRTHDAY,TV_UPDATE)
        VALUES(#{userId},#{userName},#{loginName},#{birthday},#{tvUpdate}) -->
    </insert>
</mapper>
  1. 测试
package com.steven.mybatis.sysmanage.test;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

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.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;

import com.steven.mybatis.sysmanage.dto.UserDto;
import com.steven.mybatis.sysmanage.entity.User;
import com.steven.mybatis.sysmanage.mapper.UserMapper;

public class MyBatisMapperTest {
    static Logger log = Logger.getLogger(MyBatisMapperTest.class);
    
    private SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    
    @Before
    public void init() throws IOException{
        String configFile = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(configFile);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        sqlSession = sqlSessionFactory.openSession();
    }
    
    //根据UserDto对象验证用户是否存在
    @Test
    public void testGetUserListByUserDto(){
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        UserDto userDto = new UserDto();
//      User user = new User();
//      user.setLoginName("Steven");
//      userDto.setUser(user);
        
        List<Long> ids = new ArrayList<Long>();
        ids.add(1L);
        ids.add(2L);
        ids.add(3L);
        userDto.setIds(ids);
        log.info(userMapper.getUserListByUserDto(userDto));
    }
    
    @Test
    public void testAddUser() throws IOException{   
        User user = new User();
        user.setUserName("wangwu");
        user.setLoginName("ww");
        user.setBirthday(new Timestamp(System.currentTimeMillis()));
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 
        userMapper.addUser(user);
        //测试通过mapper配置文件中的selectKey标签返回userId
        log.info(user.getUserId());
        
        //注意:增删改操作的时候,需要提交事务  sqlSession.commit();
        sqlSession.commit();
        sqlSession.close();
    }
    
}

猜你喜欢

转载自www.cnblogs.com/steven0325/p/11207600.html