[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();
	}
	
}
posted @ 2019-07-18 15:23  Steven0325  阅读(329)  评论(0编辑  收藏  举报