mybatis的了解

本文详细介绍了Mybatis框架的核心组件SqlSession的使用方法,包括#{}与${}的区别、传递参数(如pojo对象、hashmap)的方式,以及resultType在映射到不同类型的Java对象上的应用。同时,文章还探讨了Mybatis的全局配置文件SqlMapConfig.xml的作用和配置选项,强调了在实际开发中动态代理的使用和配置规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、mybatis的框架结构



过程说明:

1、 mybatis配置

SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。

mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂

3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。

5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sqlid即是Mapped statementid

6、 Mapped Statementsql执行输入参数进行定义,包括HashMap、基本类型、pojoExecutor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

7、 Mapped Statementsql执行输出结果进行定义,包括HashMap、基本类型、pojoExecutor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

注意事项:

1.代码说明

public class User_select {
	public static void main(String[] args) throws IOException {
		
		//加载配置文件
		String resource = "SqlMapConfig.xml";
		InputStream inputStream  = Resources.getResourceAsStream(resource);
		
		//根据mytais的配置创建SqlSessionFactory
		
		SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		
		//根据SqlSessionFactory创建SqlSession
		
		SqlSession sqlSession = sqlSessionFactory.openSession();
		
		//通过sqlSession查询用户信息(发起数据库操作)
		//第一个参数statement:指定mapper映射文件中statement的id,指定 时需要前边加上statement所属的命名空间
		//第二个参数parameter,指定 输入参数
		//selectOne返回的是单条记录,如果select返回多条记录(list集合),使用selectOne会报错
		//根据映射文件中的resultType指定输出类型
		User user = sqlSession.selectOne("test.findUserById", 10);
		
		//遍历查询结果
		System.out.println(user);
		
		//查询用户列表
		//selectList表示查询一个结果集(可以是一条或多条)
		List<User> list = sqlSession.selectList("test.findUserList", "张");
		
		System.out.println(list.size());
		
		//关闭sqlSession
		
		sqlSession.close();
		
	}
}

2、sqlSession的使用注意事项

SqlSession使用方法

SqlSessionFactoryBuilder:用于创建SqlSessionFactory,将SqlSessionFactoryBuilder当成工具类使用。

 

SqlSessionFactory:会话工厂,用于创建SqlSessionSqlSessionFactory一旦创建成功,不用每次创建工厂,建议单例模式使用工厂。如果和spring整合后,由spring来管理SqlSessionFactoryspring容器中SqlSessionFactory是一个单例对象

 

SqlSession(重点)是一个面向用户的接口,通过SqlSessionFactory获取SqlSession,每次数据操作都需要创建新的SqlSessionSqlSession 不是线程安全,最佳应用场合是方法体内,在方法中定义一个SqlSession局部变量。


二、mybatis作为持久层框架在开发过程中常用的两种配置方式

1、原始dao层的使用方式

这种情况:需要开发dao接口和dao的实现类。

public interface UserDao {
	
	//根据用户id查询用户信息
	public User findUserById(int id) throws Exception;
	
	//添加用户
	public void insertUser(User user) throws Exception;
	
	//查询用户列表
	public List<User> findUserList()throws Exception;
}
public class UserDaoImpl implements UserDao {

	// 注入SqlSessionFactory
	private SqlSessionFactory sqlSessionFactory;

	public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
		this.sqlSessionFactory = sqlSessionFactory;
	}

	@Override
	public User findUserById(int id) throws Exception {

		// 根据SqlSessionFactory创建SqlSession

		SqlSession sqlSession = sqlSessionFactory.openSession();

		// 通过sqlSession查询用户信息(发起数据库操作)
		// 第一个参数statement:指定mapper映射文件中statement的id,指定 时需要前边加上statement所属的命名空间
		// 第二个参数parameter,指定 输入参数
		// selectOne返回的是单条记录,如果select返回多条记录(list集合),使用selectOne会报错
		// 根据映射文件中的resultType指定输出类型
		User user = sqlSession.selectOne("test.findUserById", id);

		// 遍历查询结果
		// System.out.println(user);

		return user;
	}

	@Override
	public void insertUser(User user) throws Exception {
		// 根据SqlSessionFactory创建SqlSession

		SqlSession sqlSession = sqlSessionFactory.openSession();

		sqlSession.insert("test.insertUser", user);

		sqlSession.commit();

		sqlSession.close();

	}

	@Override
	public List<User> findUserList() throws Exception {
		// 根据SqlSessionFactory创建SqlSession

		SqlSession sqlSession = sqlSessionFactory.openSession();

		// 通过sqlSession查询用户信息(发起数据库操作)
		// 第一个参数statement:指定mapper映射文件中statement的id,指定 时需要前边加上statement所属的命名空间
		// 第二个参数parameter,指定 输入参数
		// selectOne返回的是单条记录,如果select返回多条记录(list集合),使用selectOne会报错
		// 根据映射文件中的resultType指定输出类型

		// 查询用户列表
		// selectList表示查询一个结果集(可以是一条或多条)
		List<User> list = sqlSession.selectList("test.findUserList", "张");

		System.out.println(list.size());
		return list;
	}

}

具体代码参考: https://github.com/libolibolibo/mybatis1217_1.git

2、使用mybatis的动态代理的方法

2.1、使用mybatis动态代理的好处

在开发过程中,只需要开发dao接口、接口对应的mapper.xml文件就可以了;

2.2、使用mybatis动态代理开发的原理

通过mybatis动态代理规则的配置,根据映射文件会生成dao接口实现类的代理对象,这个就相当于mybatis自己通过映射文件的配置,自己生成类dao接口的实现类,进而动态的调用statement语句;

2.3、使用mybatis的动态代理的规则配置

2.31、 mapper.xml中将namespace设置为mapper.java接口的全限定名

2.32、 mapper.java接口的方法名和mapper.xmlstatementid保持一致。

2.33、 mapper.java接口的方法输入参数类型和mapper.xmlstatementparameterType保持一致

2.34、 mapper.java接口的方法输出 结果类型和mapper.xmlstatementresultType保持一致

2.4注意:mybatis在调用查询的时候是调用selectOne还是selectList取决于dao接口的返回值,但是 resultType保持不变;

Mybatis生成代理对象时,根据statement的标签决定调用 SqlSession的方法(selectinsertupdate..)

根据上边接口方法返回值 类型来决定 是调用 selectOne还是selectList,如果返回的是单个对象,动态代理调用selectOne(),如果返回的是集合对象,动态代理调用selectList()

<select id="findUserById" parameterType="int" resultType="user">
		
		SELECT * FROM USER WHERE id = #{id}
	
	</select>
<select id="findUserList" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User" >
	  SELECT * FROM USER WHERE username LIKE '%${value}%'
	</select>
public interface UserMapper {
	
	//根据用户id查询用户信息
	public User findUserById(int id) throws Exception;
	
	//查询用户列表
	public List<User> findUserList(String username)throws Exception;

}

具体的代码示例: https://github.com/libolibolibo/mybatis1217_2.git

三、mybatis框架的全局的配置文件(一般名称为SqlMapConfig.xml)说明,这个在开发过程中使用比较少,一般在与spring整合后就不使用该文件了,但是要了解

1、全局配置文件的作用

SqlMapConfig.xml作为mybatis的全局配置文件,配置内容包括:数据库环境、mapper定义、全局参数设置......

  • properties(属性)

properties属性文件一般使用在,将数据库连接参数单独在一个properties文件中配置,好处是:方便系统升级维护。

  • settings(全局配置参数)

mybaits框架运行设置一些全局配置参数,比如:开启二级缓存 ,开启延迟载。。。

ibatis中有一些设置性能参数(最大线程数、最大请求数。。),在mybatis中没有这些性能参数。

注意:设置全局参数会影响mybatis框架运行,谨慎设置。

  • typeAliases(类型别名)

在parameterTyperesultType设置时,为了方便编码,定义别名代替pojo的全路径。

  • typeHandlers(类型处理器)

类型处理器用于java类型和jdbc类型映射:

Mybatis提供 的类型处理器满足日常需要。

  • objectFactory(对象工厂)

  • plugins(插件)

  • environments(环境集合属性对象)

  • environment(环境子属性对象)

  • transactionManager(事务管理)

  • dataSource(数据源)

  • mappers(映射器)


<?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="db.properties" />
	
	<!-- 全局配置参数 -->
	<!-- settings></settings> -->
	
	<!-- 定义别名 -->
	<typeAliases>
	    <!-- 单个别名定义
		type:pojo的路径 
		alias:别名的名称
		-->
		<!-- <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> -->
		<!-- 批量别名定义
		name:指定包名,将包下边的所有pojo定义别名 ,别名为类名(首字母大写或小写都行)
		 -->
		<package name="cn.itcast.mybatis.po"/>
	</typeAliases>
	
	<!-- 和spring整合后 environments配置将废除 -->
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}"/>
				<property name="url" value="${jdbc.url}"/>
				<property name="username" value="${jdbc.username}"/>
				<property name="password" value="${jdbc.password}"/>
			</dataSource>
		</environment>
	</environments>

	<!-- 配置mapper映射文件 -->
	<mappers>
	    <!-- resource方式
	    在UserMapper.xml,定义namespace为mapper接口的地址,映射文件通过namespace找到对应的mapper接口文件
	     -->
		<!-- <mapper resource="sqlmap/UserMapper.xml" /> -->
		<!-- class方式
		class:指定 mapper接口的地址
		遵循规则:将mapper.xml和mapper.java文件放在一个目录 且文件名相同
		 -->
		<!-- <mapper class="cn.itcast.mybatis.mapper.UserMapper"/> -->
	
		
		<!--批量mapper扫描
		遵循规则:将mapper.xml和mapper.java文件放在一个目录 且文件名相同
		  -->
		<package name="cn.itcast.mybatis.mapper"/>
		
		
	</mappers>
</configuration>

四、mybatis的映射文件配置说明(一般命名为xxxMapper.xml)

(一)、主键返回问题

需求 :对于新增的记录,需要将主键返回到pojo中,就可以从pojo中获取新添加的记录id

自增主键生成 Uuid主键生成时机区别:

  • 自增主键在insert语句执行后生成 的。
  • Uuid主键在insert语句执行前生成 的。

1、Mysql 自增主键获取

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
	
	<!-- 
	keyProperty:将主键设置到pojo中哪个属性中
	order:selectKey中sql执行的时机
	resultType:selectKey中sql执行的结果类型
	LAST_INSERT_ID:是insert后获取自增主键值 
	 -->
	<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
	     select LAST_INSERT_ID()
	</selectKey>
	insert into user(username,birthday,sex,address,detail,score)
	 values(#{username},#{birthday},#{sex},#{address},#{detail},#{score})
	</insert>

2、  Uuid主键获取

Uuid主键在insert语句执行前生成 的

 

如果使用uuid获取主键,定义selectkey

 

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<!--
keyProperty:将主键设置到pojo中哪个属性中
order:selectKey中sql执行的时机
resultType:selectKey中sql执行的结果类型
LAST_INSERT_ID:是insert后获取自增主键值
 -->
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
     select uuid()
</selectKey>
insert into user(id,username,birthday,sex,address,detail,score)
 values(#{id},#{username},#{birthday},#{sex},#{address},#{detail},#{score})
</insert>

如果不用selectKey,也可以在调用SqlSession.insert()前,在输入参数设置id(生成uuid,设置到userid属性中。)


3、Oracle主键返回

Oracle没有自增主键,使用oracle的序列(可以生成流水号,类似 自增主键)生成主键。

 

通过序列获取流水号方法:

Select 序列名.next.val from dual

 

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<!--
keyProperty:将主键设置到pojo中哪个属性中
order:selectKey中sql执行的时机
resultType:selectKey中sql执行的结果类型
LAST_INSERT_ID:是insert后获取自增主键值
 -->
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
     Select 序列名.next.val from dual
</selectKey>
insert into user(id,username,birthday,sex,address,detail,score)
 values(#{id},#{username},#{birthday},#{sex},#{address},#{detail},#{score})
</insert>

(二)、parameterType(输入类型)

parameterType:用于设置输入参数的类型。


1、#{}与${}

 

#{}:表示占位符,如果获取简单类型,#{}中可以使用value或其它名称 。有效防止sql注入。使用#{}设置参数无需考虑参数的类型。

如果使用#{}比较日期字段,select * from tablename where birthday >=#{birthday}

 

${}:表示sql拼接,如果获取简单类型,${}中只能使用value 。无法防止sql注入。使用${}设置参数必须考虑参数的类型,比如:使用oracle查询条件是日期类型,如果使用${},必须人为将${}两边加单引号通过to_date转日期。(只是表示简单的字符串拼接,而没有mybatis的映射关系)

Select * from table where birthday >=to_date(‘${birthday}’,’yyyy-MM-dd’)

 

在没有特殊要求的情况下,建议使用#{}占位符

有些情况必须使用${}

比如:需要动态拼接表名,Select * from ${tablename}

动态拼接排序字段:select * from tablename order by ${username} desc

2、 传递pojo对象

2.1、parameterType指定 输入参数为pojo自定义对象时,在sql中使用${}#{}获取pojo的属性。

 

2.2、 包装对象使用

开发中使用pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(是另一个pojo),使用包装对象传递输入参数。

 

定义包装对象将查询条件(pojo)以类组合的方式包装起来。

 

parameterType使用包装对象:

包装类

public class QueryVo {
	
	//用户查询条件
	//为了查询条件扩展方便,基于po的基础上自定义的pojo,继承于Po
	private UserCustom userCustom;
	
	private User user;
	
	private int[] ids;

	public UserCustom getUserCustom() {
		return userCustom;
	}

	public void setUserCustom(UserCustom userCustom) {
		this.userCustom = userCustom;
	}

	public User getUser() {
		return user;
	}

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

	public int[] getIds() {
		return ids;
	}

	public void setIds(int[] ids) {
		this.ids = ids;
	}
	
	//基它的查询条件

}

public class UserCustom extends User {
	
	//学生类型,扩展字段
	private String groupid;

	public String getGroupid() {
		return groupid;
	}

	public void setGroupid(String groupid) {
		this.groupid = groupid;
	}
	
	

}

映射文件.xml

<!-- 查询用户列表 根据用户名称和用户性别查询用户列表 -->
	<select id="findUserList" parameterType="queryVo" resultType="user">
		select id,username username_ from user
		<!-- where自动将第一个and去掉 -->
		<where>
	     <!-- 这里调用 queryVo的getUser方法获 取user的值 -->
			<if test="user!=null">
				<!-- 这里调用 queryVo的user的getUsername方法获取username的值 -->
				<if test="user.username!=null and user.username!=''">
					and user.username = #{user.username}
				</if>
				<if test="user.sex!=null and user.sex!=''">
					and user.sex = #{user.sex}
				</if>
			</if>
	<if test="ids!=null">
		<foreach collection="ids" item="id" open="AND ("
			separator="OR" close=")">
			id =#{id} 
		</foreach>

		<!-- AND id IN (10,89,16) -->
		<!-- <foreach collection="ids" item="id" open="AND id IN ("
			separator="," close=")">
			#{id} 
		</foreach> -->
	</if>		
		</where>
	</select>


2.3、 传递hashmap

parameterType指定 hashmap传递输入参数,#{}${}中引用mapkey

 

Sql映射文件定义如下:

<!-- 传递hashmap综合查询用户信息 -->
<select id="selectUserByHashmap" parameterType="hashmap" resultType="user">
   select * from user where id=#{id} and username like '%${username}%'
</select>




(三)、 resultType输出映射到java对象上


1、返回pojo

resultType:将sql查询结果集映射为java对象。要求sql查询的字段名和resultType指定pojo的属性名一致,才能映射成功。

如果全部字段和pojo的属性名不一致,映射生成 的java对象为空,只要有一个字段和pojo属性名一致,映射生成 的java对象不为空。

 

结论:sql查询字段名和pojo的属性名一致才能映射成功。

 

 

不管select返回的是单个 对象还是集合对象,resultType要指定单条记录映射的java对象。



2、返回简单类型

如果 sql查询的结果集只有一行且一列,resultType可以返回简单类型。


3、 返回hashmap

输出pojo对象可以改用hashmap输出类型,将输出的字段名称作为mapkeyvalue为字段值。

 

l Mapper.xml
<select id="findUserListReturnMap" parameterType="queryVo"  resultType="hashmap">
 	select id,username username_ from user where username = #{user.username} and sex=#{user.sex}
 </select>
l Mapper.java
Public Map  findUserListReturnMap(QueryVo queryVo);

建议不使用map作为返回值 ,因为需要对key在代码中硬编码。


(四)、mybatis的动态sql

Mybatis提供 了很多标签,用于拼接sql语句。

  • if标签
  • where标签
  • set标签
  • foreach标签

<?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="cn.itcast.mybatis.mapper.UserMapperCustom">

	<!-- sql片段 -->
	<!-- 
	用户查询条件
	id:在namespace唯 一标识 
	建议以单表抽取查询条件 
	 -->
	 <sql id="query_user_where">
	 
	     <!-- 这里调用 queryVo的getUser方法获 取user的值 -->
			<if test="user!=null">
				<!-- 这里调用 queryVo的user的getUsername方法获取username的值 -->
				<if test="user.username!=null and user.username!=''">
					and user.username = #{user.username}
				</if>
				<if test="user.sex!=null and user.sex!=''">
					and user.sex = #{user.sex}
				</if>
				
				
				
				
			</if>
	<if test="ids!=null">
		<!-- 根据传入id数组构造查询条件 -->
		<!-- AND (id =10 OR id =89 OR id=16) -->
		<!-- 遍历ids数组 
		
		collection:集合,ids数组
		item:遍历的每个对象
		open:开始遍历时拼接的sql
		separator:遍历的间隔符号
		close:结束 遍历时拼接的sql
		 -->
		<foreach collection="ids" item="id" open="AND ("
			separator="OR" close=")">
			id =#{id} 
		</foreach>

		<!-- AND id IN (10,89,16) -->
		<!-- <foreach collection="ids" item="id" open="AND id IN ("
			separator="," close=")">
			#{id} 
		</foreach> -->
	</if>
			
	 </sql>
	 
	 <!-- 定义resultMap,将用户查询的字段和user这个pojo的属性名作一个对应关系  -->
	 <!-- 
	 type:最终映射的java对象。
	 id:resultMap的唯一标识 
	  -->
	 <resultMap type="user" id="userListResultMap">
	 	<!-- id标签:查询结果集的唯 一标识 列(主键或唯 一标识 )
	 	column:sql查询字段名(列名)
	 	property:pojo的属性名
	 	
	 	result标签:普通列
	 	 -->
	 	
	 	<id column="id_" property="id"/>
	 	<result column="username_" property="username"/>
	 	<result column="birthday_" property="birthday"/>
	 	
	 
	 </resultMap>

	<!-- 查询用户列表 根据用户名称和用户性别查询用户列表 -->
	<select id="findUserList" parameterType="queryVo" resultType="user">
		select id,username username_ from user

		<!-- where自动将第一个and去掉 -->
		<where>
		    <!-- 
		    refid:指定 sql片段的id,如果要引用其它命名空间的sql片段,需要前边加namespace
		    
		     -->
			<include refid="query_user_where"/>
		</where>
	</select>
	
	<!-- 查询用户列表 根据用户名称和用户性别查询用户列表 -->
	<select id="findUserListResultMap" parameterType="queryVo" resultMap="userListResultMap">
		select id id_,username username_,birthday birthday_ from user

		<!-- where自动将第一个and去掉 -->
		<where>
		    <!-- 
		    refid:指定 sql片段的id,如果要引用其它命名空间的sql片段,需要前边加namespace
		    
		     -->
			<include refid="query_user_where"/>
		</where>
	</select>
	

	<!-- 查询用户列表总数 用于分页查询 -->
	<select id="findUserCount" parameterType="queryVo" resultType="int">
		select count(*) from user
		<!-- where自动将第一个and去掉 -->
		<where>
		    <!-- 
		    refid:指定 sql片段的id,如果要引用其它命名空间的sql片段,需要前边加namespace
		    
		     -->
			<include refid="query_user_where"/>
		</where>
	</select>



</mapper>

具体代码示例,看上面两个项目的代码吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值