[Spring + SpringMVC + Mybatis] study notes frame (IX): Mybatis main configuration and mapping files

Chapter 9 Mybatis main configuration files and mapping files

ZXQOgI.png

9.1 were developed in two ways with Mybatis

Mybatis in using formal development environment in two ways:

1) The original class interface and implementation manner
disadvantages:

  • Repeat the code too much, sqlSession operation
  • id hard-coded statement impact of future maintenance

2) (emphasis) on development mode mapper proxy
mybatis automatically create proxy object implementation class dao interface according to some rules
rules:

  • userMapper.xml the namespace must be specified as UserMapper (corresponding to the case of 8 speaking IUserDao) of the fully qualified class name
  • userMapper.xml in statement (i.e. sql statement) is designated as the id of the interface method corresponding UserMapper name
  • UserMapper.xml statement consistent with the type of the input parameters and corresponding method UserMapper parameter type
  • userMapper.xml return type and a corresponding method of statement UserMapper the same return type

9.2 The main configuration file config.xml Detailed

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

9.3 Detailed mapping file mapper.xml

  • Input parameters parameterType
    • Simple type of single parameter
      needs: query user information based on user id
    • Simple type of multiple parameters
      demand: if there is by login name and password to authenticate the user
    • Wrapper class object as an input parameter query
      needs: to query a list of matching users based on user input interface name or login name
  • Dynamic sql
    • if the label and where the label
    • sql fragment
    • foreach
  • Output parameters resultType / resultMap
    • Simple output type Integer (can be written as int, i.e. with alias, which is automatically set, need not be provided in the main configuration file) String Long (can be written as long)
    • Output target
    • HashMap output
    • resultMap plant output (when not follow the naming database design rules, java design not follow the naming convention used -> manually set the correspondence between the database table and column names java properties)

9.4 based mapper proxy Mybatis of Demo

ZXlK54.png

9.4.1 Test data preparation

ZX3TET.png

ZX37UU.png

jdbc property profile:

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 entity class, Dao interfaces

8.4.2 User entity class with the same.

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

8.4.2 Interface with the Dao UserMapper substantially the same, here adds several methods.

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 main configuration file

<?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 Object mapping file

<?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 Testing

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);
    }
    
    //增、删、改省略
    
}

All users query result comparison of three ways:

方式一: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 dynamic sql

  • if the label and where the label
    See, for example 9.4.
  • foreach
    needs: the need to query all the user id specified information collection
    SELECT * FROM M_USER WHERE USER_ID IN (1,2,3)
  • sql fragment
    generic sql statement extracted referred sql fragments, applied to different methods
  • Return to the main key to increase the recording
    <!--以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. Increase ids wrapper class attribute UserDto
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 file
<?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. test
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();
    }
    
}

Guess you like

Origin www.cnblogs.com/steven0325/p/11207600.html