SSM之mybatis(1/2)
目录
Mybatis框架
SqlMapConfig.xml讲解
Mybatis的全局配置文件 SqlMapConfig.xml ,配置内容如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象) //该配置内容整合时弃用
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源) (与springmvc整合后弃用)
mappers(映射器)
properties 属性
需求:
将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties的属性值。
在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。
将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其他xml可以引用该db.properties。
properties特性:
注意:mybatis将按照下面的顺序来加载属性
- 在properties元素体内定义的属性首先被读取。
- 然后会读取properties元素中resource或url加载的属性,它会覆盖已读取的同名属性。
- 最后读取parameterType传递的属性,它会覆盖已读取的同名属性。
建议:
不要再properties元素体内添加任何属性值,只将属性值定义在properties文件中。
在properties文件中定义属性名要有一定的特殊性:如:xxxx.xxxx.xxxx...
db.properties 文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
SqlMapConfig.xml文件:
<!-- 加载属性文件 -->
<properties resource="db.properties">
<!-- properties中还可以配置一些属性名和属性值 -->
<!-- <property name="" value=""/> -->
</properties>
<!-- 和spring整合后environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理,事务控制由mybatis -->
<transactionManager type="JDBC" />
<!-- 数据库连接池,由mybatis管理 -->
<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>
settings 属性
mybatis框架在运行时可以调整一些运行参数。
比如:开启二级缓存、开启延迟加载 ... ...
全局参数将会影响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>
<!-- 针对单个别名定义
type:类型的路径
alias:别名 -->
<typeAlias type="com.mybatis.bean.User" alias="user"/>
</typeAliases>
Mapper.xml 文件:
<select id="findUserById" parameterType="int" resultType="user">
多个别名定义:
SqlMapConfig.xml 文件:
<!-- 定义别名 -->
<typeAliases>
<!-- 批量别名定义
指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大小写不限) -->
<package name="com.mybatis.bean"/>
</typeAliases>
typeHandlers 属性
mybatis中通过typeHandlers完成jdbc类型和java类型的转换。
通常情况下,mybatis提供的类型处理器满足日常需求,不需要自定义。
mybatis支持类型处理器:
类型处理器 |
Java类型 |
Jdbc类型 |
BooleanTypeHandler |
Boolean,boolean |
任何兼容的布尔值 |
ByteTypeHandler |
Byte,byte |
任何兼容的数字或字节类型 |
LongTypeHandler |
Long,long |
任何兼容的数字或长整形 |
ShortTypeHandler |
Short,short |
任何兼容的数字或短整型 |
IntegerTypeHandler |
Integer,int |
任何兼容的数字或整型 |
DoubleTypeHandler |
Double,double |
任何兼容的数字或双精度浮点型 |
FloatTypeHandler |
Float,float |
任何兼容的数字或单精度浮点型 |
BigDecimalTypeHandler |
BigDecimal |
任何兼容的数字或十进制小数类型 |
StringTypeHandler |
String |
char和varchar类型 |
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-任何兼容的字符串类型,作为代码存储(而不是索引) |
mapper 属性
通过resource加载单个映射文件:
<!-- 加载映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml"/>
<!-- 通过resource方法一次加载一个映射文件 -->
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
通过mapper接口加载单个mapper映射文件:
<!-- 加载映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml"/>
<!-- 通过mapper接口加载单个映射文件
遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中
前提:使用mapper代理方法 -->
<mapper class="com.mybatis.mapper.UserMapper"/>
</mappers>
批量加载mapper(推荐使用):
<!-- 加载映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml"/
<!-- 批量加载mapper
指定mapper接口的包名,mybatis自动扫描下边所有mapper接口进行加载
遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中
前提:使用mapper代理方法 -->
<package name="com.mybatis.mapper"/>
</mappers>
mapper代理开发dao
思路
程序员需要编写mapper.xml映射文件
程序员编写mapper接口需要遵循一些开发规则,mybatis可以自动生成mapper接口实现类代理对象。
开发规范:
- 在mapper.xml中namespace等于mapper接口地址。
- mapper.java接口中的方法名和mapper.xml中statement的id一致。
- mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致。
- mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。
<mapper namespace="com.mybatis.mapper.UserMapper">
… …
</mapper>
输入映射(传递pojo的包装对象)
对于需要传入查询条件很复杂(可能包括用户信息、其他信息,比如商品、订单等),建议使用自定义的包装类的pojo。
在包装类型的pojo中将复杂的查询条件包装进去。
对于综合查询,建议parameterType使用包装的pojo,有利于系统扩展。
输出映射
resultType:
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象;
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
resultMap:
mybatis中只用resultMap完成高级输出结果映射。
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间做一个映射关系。
- 定义resultMap;
- 使用resultMap作为statement的输出映射类型;
<!-- 使用resultMap进行输出映射
resultMap:指定定义的resultMap的id,如果这个resultMap在其他的mapper文件,前边需要加namespace -->
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
select id id_,username username_ from user where id=#{value}
</select>
<!-- 定义resultMap
将select id id_,username username_ from user 和User类中的属性做一个映射关系
type:resultMap最终映射的java对象类型,可以使用别名
id:对resultMap的唯一标识 -->
<resultMap type="user" id="userResultMap">
<!-- id表示查询结果集中唯一标识
column:查询出来的列名
property:type指定的pojo类型中的属性名
最终resultMap对colimn和property做一个映射关系(对应关系) -->
<id column="id_" property="id"/>
<!-- result:对普通名映射定义
column:查询出来的列名
property:type指定的pojo类型中的属性名
最终resultMap对colimn和property做一个映射关系(对应关系) -->
<result column="username_" property="username"/>
</resultMap>
resultType和resultMap小结:
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间做一个映射关系。
动态SQL
什么是动态SQL
mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。
案例
需求一:用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql。
对查询条件进行判断,如果输入参数不为空才进行查询条件拼接。使用sql片段。
定义SQL片段:
<!-- 定义sql片段
id:sql片段的唯一标识
经验:是基于单表来定义sql片段,这样的话这个sql片段可重用性才高
在sql片段中不要包括where
-->
<sql id="query_user_where">
<if test="userCustom!=null">
<if test="userCustom.username!=null and userCustom.username!=''">
and user.username like '%${userCustom.username}%'
</if>
<if test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex=#{userCustom.sex}
</if>
</if>
</sql>
引用SQL片段:
<!-- 用户信息综合查询
#{userCustom.sex}:取出pojo包装对象中性别值
${userCustom.username}:取出pojo包装对象中用户名称 -->
<select id="findUserList" parameterType="com.mybatis.bean.UserQueryVo"
resultType="com.mybatis.bean.UserCustom">
select * from user
<!-- where可以自动去掉条件中的第一个and -->
<where>
<!-- 引用sql片段的id,如果refid指定的id不再本mapper中,需要前面加namespace -->
<include refid="query_user_where"></include>
<!-- 在这里还要引用其他的sql片段 -->
</where>
</select>
需求二:使用foreach
在用户查询列表和查询总数的statement中增加多个id输入查询
Sql语句两种方法:
select * from user where id=1 or id=2 or id=4
select * from user where id in(1,2,4)
<!-- 定义sql片段
id:sql片段的唯一标识
经验:是基于单表来定义sql片段,这样的话这个sql片段可重用性才高
在sql片段中不要包括where
-->
<sql id="query_user_where">
<if test="userCustom!=null">
… …
<if test="ids!=null">
<!-- 使用foreach遍历传入ids
collection:指定输入对象中集合属性
item:每个遍历生成对象值
open:开始遍历时拼接的串
close:结束遍历时拼接的串
separator:遍历的两个对象中需要拼接的串 -->
<!-- 使用实现下边的sql拼接
and (id=1 or id=2 or id=4) -->
<foreach collection="ids" item="user_id" open="and (" close=")" sparator="or">
<!-- 每个遍历需要拼接的串 -->
id=#{user_id}
</foreach>
<!-- 实现“and id in(1,2,4)”拼接 -->
<foreach collection="ids" item="user_id" open="and id in(" close=")" separator=",">
#{user_id}
</foreach>
</if>
</if>
</sql>
琐碎知识点小结
自增主键返回
Mysql自增主键,执行insert提交之前自动生成一个自增主键。
通过mysql函数获取到刚插入记录的自增主键:LAST_INSERT_ID()
是在insert之后调用此函数。
非自增主键返回(使用uuid())
使用mysql的uuid()函数生成主键,需要修改表中id字段类型为string,长度设置成35位。
执行思路:
先通过uuid() 查询到主键,将主键输入到sql语句中。
执行uuid() 语句顺序相对于insert语句之前执行。
<!-- 使用mysql的uuid()生成主键
执行过程:
首先通过uuid()得到主键,将之间设置到user对象的id属性中
其实在insert执行时,从user对象中取出id属性值 -->
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
select uuid()
</selectKey>
Insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address})
#{}和${}的区别
#{}表示一个占位符,#{}接收输入参数,类型可以是简单类型,pojo,hashmap。
如果接收简单类型,#{}中可以value或其他名称。
#{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象的属性值。
${}表示一个拼接符,会引起用sql注入,所以不建议使用${}。
${}接收输入参数,类型可以是简单类型,pojo,hashmap。
如果接收简单类型,${}中只能写成value。
${}接收pojo对象值,通过OGNL读取对象中的属性值,通过通过属性.属性.属性...的方式获取对象的属性值。
mybatis和hibernate本质区别和应用场景
Hibernate:是一个标准的ORM框架(对象关系映射)。入门门槛较高的,不需要程序学sql,sql语句自动生成。对sql语句进行优化、修改比较困难的。
应用场景:
适用于需求变化不多的中小型项目,比如:后台管理系统,erp、orm、oa....
Mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。Mybatis是一个不完全的ORM框架,虽然程序员自己写sql,mybatis也可以实现映射(输入映射、输出映射)。
应用场景:
适用于需求变化较多的项目,比如:互联网项目,京东、淘宝等电商。
企业进行技术选型,以低成本,高回报作为技术选型的原则,根据项目组的技术力量进行选择。
下一节 SSM之mybatis(2/2)