{ } 和 ${ } 的区别
#{ }表示一个占位符号,通过#{ }可以实现 preparedStatement 向占位符中设置值,自动进行java 类型和 jdbc 类型转换,
#{ } 可以有效防止sql注入。#{ } 可以接收简单类型值或 pojo 属性值(通过 OGNL 读取对象中的值,属性.属性.属性..方式获取对象属性值)。 如果 parameterType 传输单个简单类型值,#{ }括号中可以是 value 或其它名称。{ }可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换,
{}括号中只能是 value。
parameterType 和 resultType 区别
parameterType:指定输入参数类型,mybatis 通过 ognl 从输入对象中获取参数值拼接在 sql 中。
resultType:指定输出结果类型,mybatis 将 sql 查询结果的一行记录数据映射为 resultType 指定类型的对象。
SqlMapConfig.xml 文件
Mybatis 的全局配置变量,配置内容和顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
properties 属性
需求:将数据库连接参数单独配置在 db.properties 中,只需要在 SqlMapConfig.xml 中加载该配置文件 db.properties 的属性值。在 SqlMapConfig.xml 中就不需要直接对数据库的连接参数进行硬编码了。方便以后对参数进行统一的管理,其他的xml文件可以引用该 db.properties 。
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_test?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
那么 SqlMapConfig.xml 中的配置变成如下:
<!--加载配置文件-->
<properties resource="db.properties"></properties>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理,事务由 Mybatis 控制-->
<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>
配置完成后我们测试一下是否能够和刚才一样的能够成功呢?那么我就先在db.properties中把数据库密码故意改错,看是否是正确的?不出意外的话是会报错的。
注意: MyBatis 将按照下面的顺序来加载属性:
在 properties 元素体内定义的属性首先被读取。
然后会读取 properties 元素中 resource 或 url 加载的属性,它会覆盖已读取的同名属性。
最后读取 parameterType 传递的属性,它会覆盖已读取的同名属性。
因此,通过parameterType传递的属性具有最高优先级,resource或 url 加载的属性次之,最低优先级的是 properties 元素体内定义的属性。
建议:
不要在 properties 元素体内添加任何属性值,只将属性值定义在 db.properties 文件之中。
在 db.properties 文件之中定义的属性名要有一定的特殊性。如 xxx.xxx.xxx
settings(全局配置参数)
Mybatis 框架在运行时可以调整一些运行参数
比如:开启二级缓存、开启延迟加载。。。
typeAliases(类型别名)
需求:
在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。
如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
Mybatis支持的别名:
别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
自定义别名:
在 SqlMapConfig.xml 中配置:(设置别名)
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="cn.zhisheng.mybatis.po.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="cn.zhisheng.mybatis.po"/>
<package name="其它包"/>
</typeAliases>
在 UserMapper.xml 中引用别名:( resultType 为 user )
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>测试结果:
typeHandlers(类型处理器)
mybatis中通过typeHandlers完成jdbc类型和java类型的转换。
通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义.
mybatis支持类型处理器:
| 类型处理器 | Java类型 | JDBC类型 |
|---|---|---|
| BooleanTypeHandler | Boolean,boolean | 任何兼容的布尔值 |
| ByteTypeHandler | Byte,byte | 任何兼容的数字或字节类型 |
| ShortTypeHandler | Short,short | 任何兼容的数字或短整型 |
| IntegerTypeHandler | Integer,int | 任何兼容的数字和整型 |
| LongTypeHandler | Long,long | 任何兼容的数字或长整型 |
| FloatTypeHandler | Float,float | 任何兼容的数字或单精度浮点型 |
| DoubleTypeHandler | Double,double | 任何兼容的数字或双精度浮点型 |
| BigDecimalTypeHandler | BigDecimal | 任何兼容的数字或十进制小数类型 |
| StringTypeHandler | String | CHAR和VARCHAR类型 |
| ClobTypeHandler | String | CLOB和LONGVARCHAR类型 |
| NStringTypeHandler | String | NVARCHAR和NCHAR类型 |
| NClobTypeHandler | String | NCLOB类型 |
| ByteArrayTypeHandler | byte[] | 任何兼容的字节流类型 |
| BlobTypeHandler | byte[] | BLOB和LONGVARBINARY类型 |
| DateTypeHandler | Date(java.util) | TIMESTAMP类型 |
| DateOnlyTypeHandler | Date(java.util) | DATE类型 |
| TimeOnlyTypeHandler | Date(java.util) | TIME类型 |
| SqlTimestampTypeHandler | Timestamp(java.sql) | TIMESTAMP类型 |
| SqlDateTypeHandler | Date(java.sql) | DATE类型 |
| SqlTimeTypeHandler | Time(java.sql) | TIME类型 |
| ObjectTypeHandler | 任意 | 其他或未指定类型 |
| EnumTypeHandler | Enumeration类型 | VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引)。 |
mappers(映射器)
使用相对于类路径的资源,如:
使用完全限定路径
如:
使用 mapper 接口类路径
如:
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
注册指定包下的所有mapper接口
如:
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
Mapper.xml 映射文件
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。
输入映射
通过 parameterType 指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型。
传递 pojo 包装对象 (重点)
开发中通过pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
定义包装对象
定义包装对象将查询条件(pojo)以类组合的方式包装起来。
UserQueryVo.java
public class UserQueryVo //用户包装类型
{
//在这里包装所需要的查询条件
//用户查询条件
private UserCustom userCustom;
public UserCustom getUserCustom()
{
return userCustom;
}
public void setUserCustom(UserCustom userCustom)
{
this.userCustom = userCustom;
}
//还可以包装其他的查询条件,比如订单、商品
}UserCustomer.java
public class UserCustom extends User //用户的扩展类
{
//可以扩展用户的信息
}UserMapper.xml 文件
<select id="findUserList" parameterType="cn.zhisheng.mybatis.po.UserQueryVo" resultType="cn.zhisheng.mybatis.po.UserCustom">
select * from user where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'
</select>UserMapper.java
//用户信息综合查询
public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;
测试代码
//测试用户信息综合查询
测试结果
输出映射
resultType
使用 resultType 进行输出映射,只有查询出来的列名和 pojo 中的属性名一致,该列才可以映射成功。
如果查询出来的列名和 pojo 中的属性名全部不一致,没有创建 pojo 对象。
只要查询出来的列名和 pojo 中的属性有一个一致,就会创建 pojo 对象。
输出简单类型
需求:用户信息综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页
实现:
<select id="findUserCount" parameterType="cn.zhisheng.mybatis.po.UserQueryVo" resultType="int">
select count(*) from user where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'
</select>//用户信息综合查询总数
public int findUserCount(UserQueryVo userQueryVo) throws Exception;
//测试用户信息综合查询总数
@Test
public void testFindUserCount() throws Exception
{
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建usermapper对象,mybatis自动生成代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建包装对象,设置查询条件
UserQueryVo userQueryVo = new UserQueryVo();
UserCustom userCustom = new UserCustom();
userCustom.setSex("男");
userCustom.setUsername("张小明");
userQueryVo.setUserCustom(userCustom);
//调用UserMapper的方法
System.out.println(userMapper.findUserCount(userQueryVo));
}注意:查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射。
输出pojo对象和pojo列表
不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的。
在mapper.java指定的方法返回值类型不一样:
1、输出单个pojo对象,方法返回值是单个对象类型
//根据id查询用户信息
public User findUserById(int id) throws Exception;
2、输出pojo对象list,方法返回值是List
//根据用户名查询用户信息
public List<User> findUserByUsername(String userName) throws Exception;
resultType总结:
输出pojo对象和输出pojo列表在sql中定义的resultType是一样的。
返回单个pojo对象要保证sql查询出来的结果集为单条,内部使用session.selectOne方法调用,mapper接口使用pojo对象作为方法返回值。
返回pojo列表表示查询出来的结果集可能为多条,内部使用session.selectList方法,mapper接口使用List对象作为方法返回值。
resultMap
resultType 可以指定 pojo 将查询结果映射为 pojo,但需要 pojo 的属性名和 sql 查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
使用方法:
1、定义 resultMap
2、使用 resultMap 作为 statement 的输出映射类型
将下面的 sql 使用 User 完成映射
select id id_, username username_ from user where id = #{value}User 类中属性名和上边查询的列名不一致。
所以需要:
1、定义 resultMap
<resultMap id="userResultMap" type="user">
<!--id表示查询结果中的唯一标识
column:查询出来的列名
property:type指定pojo的属性名
最终resultMap对column和property做一个映射关系(对应关系)
-->
<id column="id_" property="id"/>
<!--result: 对普通结果映射定义
column:查询出来的列名
property:type指定pojo的属性名
最终resultMap对column和property做一个映射关系(对应关系)
-->
<result column="username_" property="username"/>
</resultMap>2、使用 resultMap 作为 statement 的输出映射类型
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
select id id_, username username_ from user where id = #{value}
</select>3、UserMapper.java
//根据id查询用户信息,使用 resultMap 输出
public User findUserByIdResultMap(int id) throws Exception;
4、测试
//测试根据id查询用户信息,使用 resultMap 输出
@Test
public void testFindUserByIdResultMap() throws Exception
{
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建usermapper对象,mybatis自动生成代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper的方法
User user = userMapper.findUserByIdResultMap(1);
System.out.println(user);
}5、测试结果
动态 SQL
通过mybatis提供的各种标签方法实现动态拼接sql。
需求:
用户信息综合查询列表和用户信息查询列表总数这两个 statement的定义使用动态sql。
对查询条件进行判断,如果输入的参数不为空才进行查询条件拼接。
UserMapper.xml (findUserList的配置如下,那么findUserCount的也是一样的,这里就不全部写出来了)
<select id="findUserList" parameterType="cn.zhisheng.mybatis.po.UserQueryVo" resultType="cn.zhisheng.mybatis.po.UserCustom">
select * from user
<!--where可以自动的去掉条件中的第一个and-->
<where>
<if test="userCustom != null">
<if test="userCustom.sex != null and userCustom.sex != ''">
and user.sex = #{userCustom.sex}
</if>
<if test="userCustom.username != null">
and user.username like '%${userCustom.username}%'
</if>
</if>
</where>
</select>测试代码:因为设置了动态的sql,如果不设置某个值,那么条件就不会拼接在sql上
所以我们就注释掉设置username的语句
//userCustom.setUsername("张小明");测试结果:
Sql 片段
通过上面的其实看到在 where sql语句中有很多重复代码,我们可以将其抽取出来,组成一个sql片段,其他的statement就可以引用这个sql片段,利于系统的开发。
这里我们就拿上边sql 中的where定义一个sq片段如下:
<sql id="query_user_where">
<if test="userCustom != null">
<if test="userCustom.sex != null and userCustom.sex != ''">
and user.sex = #{userCustom.sex}
</if>
<if test="userCustom.username != null">
and user.username like '%${userCustom.username}%'
</if>
</if>
</sql>那么我们该怎样引用这个sql片段呢?如下:
select * from user
<where>
<!--refid: 指定sql片段的id,如果是写在其他的mapper文件中,则需要在前面加上namespace-->
<include refid="query_user_where"/>
</where>测试的话还是那样了,就不继续说了,前面已经说了很多了。
foreach
向sql传递数组或List,mybatis使用foreach解析
需求:
在用户查询列表和查询总数的statement中增加多个id输入查询。
sql语句如下:
SELECT * FROM USER WHERE id=1 OR id=10 ORid=16 或者 SELECT * FROM USER WHERE id IN(1,10,16) 在输入参数类型中添加 List ids 传入多个 id
public class UserQueryVo //用户包装类型
{
//传入多个id
private List<Integer> ids;
}修改 UserMapper.xml文件
WHERE id=1 OR id=10 OR id=16
在查询条件中,查询条件定义成一个sql片段,需要修改sql片段。
<if test="ids!=null">
<!-- 使用 foreach遍历传入ids
collection:指定输入 对象中集合属性
item:每个遍历生成对象中
open:开始遍历时拼接的串
close:结束遍历时拼接的串
separator:遍历的两个对象中需要拼接的串
-->
<!-- 使用实现下边的sql拼接:
AND (id=1 OR id=10 OR id=16)
-->
<foreach collection="ids" item="user_id" open="AND (" close=")" separator="or">
<!-- 每个遍历需要拼接的串 -->
id=#{user_id}
</foreach>
<!-- 实现 “ and id IN(1,10,16)”拼接 -->
<!-- <foreach collection="ids" item="user_id" open="and id IN(" close=")" separator=",">
每个遍历需要拼接的串
#{user_id}
</foreach> -->
</if>测试代码:
//传入多个id List<Integer> ids = new ArrayList<>(); ids.add(1); ids.add(10); ids.add(16); //将ids传入statement中 userQueryVo.setIds(ids);



京公网安备 11010502036488号