MyBatis框架
1、持久层框架、半自动化框架、支持自定义sql、存储过程和高级映射、
封装了jdbc对数据库的操作和sql参数和结果集的处理、
通过配置文件对数据库连接、数据库映射文件注册等操作、
映射文件是对表操作的sql语句,将操作与接口绑定,并且结果映射到实体类或高级映射resultMap
2、将业务代码与数据库sql分离开,便于维护。
实体类不用实现很多接口就可以与表映射,是非侵入式的方式
实现了数据库代码的高度复用,减少了重复性的代码
简单易学、sql比较灵活,接近jdbc,便于优化和处理
3、引入 mybatis-x.x.x.jar包到Maven项目的pom.xml依赖内即可开发MyBatis应用
4、MyBatis的配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
数据库连接、映射文件注册、数据库厂商标识、
加载数据库配置文件、别名、缓存、懒加载、驼峰命名、其它属性设定
</configuration>
5、映射文件 一个表对应一个实体类一个映射文件
<?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="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
6、调用API 建立数据库会话
1)加载MyBatis的配置文件得到输入流
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
2)利用输入流对象构建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
3)SqlSessionFactoryBuilder对象调用静态build(inputStream);创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory =sqlSessionFactory.build(inputStream);
4)SqlSessionFactory对象调用openSession()(默认不自动提交,更新时需要提交);创建SqlSession会话对象
SqlSession session=sqlSessionFactory.openSession();
5)获得数据操作接口的代理 或直接调用方法 UserMapper mapper=session.getMapper(UserMapper.class);
UserMapper mapper=session.getMapper(UserMapper.class);
或
User user=(User)session.selectOne("namespace.id",参数);
7、${}、#{}
${}取出的值直接拼接sql语句中,有sql注入的风险
#{}动态sql语句的占位符,是以预编译的方式,将参数设置到sql语句,没有sql注入
大多数情况下, 我们取出参数应该都要使用#{},
原生jdbc不支持占位符的位置我们就可以使用${}取值操作
比如表名,排序,或统计时,不支持占位符的地方 ${}
8、动态sql语句的拼接标签
1)if
判断标签 动态拼接sql的查询参数,其属性 test用于判断条件参数是否满足条件
<select>
select * from tb_user where
<if test="null!=uname"> uname=#{uname} and</if>
</select>
2)choose、when、otherwise
choose 元素,它有点像 Java 中的 switch 语句。当第一个when的条件满足,就拼上该查询参数,
如果都不满足,就拼上otherwise的查询参数。并且前后的 and|or等多余的串不能去除。
<select id="finds2" parameterType="com.ssm.vote.bean.User" resultType="com.ssm.vote.bean.User">
select usid,uname,pwd from tb_user
<trim prefix="where" prefixOverrides="and|or">
<choose>
<when test="null!=usid">
and usid=#{usid}
</when>
<when test="null!=uname and "" neq uname">
and uname=#{uname}
</when>
<otherwise>
and pwd=#{pwd}
</otherwise>
</choose>
</trim>
</select>
3)trim、where、set
where:加上where关键字、若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除,不能去除后面的。
<select>
select * from tb_user
<where>
<if test="null!=uname"> and uname=#{uname}</if>
<if test="null!=upwd"> and upwd=#{upwd}</if>
</where>
</select>
trim:有属性prefix="WHERE"意为设where为前缀,prefixOverrides="AND |OR "意为忽略"AND |OR "的前缀;
并且有对应的后缀和后缀忽略。
<select>
select * from tb_user
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="null!=uname"> and uname=#{uname}</if>
<if test="null!=upwd"> and upwd=#{upwd}</if>
</trim>
</select>
set:动态更新语句的解决,set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号。(前后都可)
<update id="modifyUser" parameterType="com.ssm.vote.bean.User">
update tb_user
<set>
<if test="null!=uname and "" neq uname ">
uname=#{uname},
</if>
<if test="null!=uname and "" neq uname ">
pwd=#{pwd},
</if>
</set>
where usid=#{usid}
</update>
4)foreach
批量插入时可用,属性collection="list" 默认名称 list ,可以根据@param("users")改变名称
item="user"指定集合循环的对象,设参数时用user.参数名称,separator="," 迭代之间分割符,
open="(" 表示集合开始符号、 close=")" 集合结束符号
5)bind 绑定 _parameter为内置参数 代表接口传入的参数 如果为一个对象 _parameter.getU_name(),如果一个简单类型 String name -->_parameter代表;如果多个 即封装成Map _parameter.get(key)获取
<select id="findLike" parameterType="users" resultType="users">
<bind name="_name" value="'%'+_parameter.getU_name()+'%'"></bind>
select u_id,u_name,u_age,t_id from db_user where u_name like #{_name}
</select>
内置参数
_parameter:给接口参数 绑定 添加一些内容
_databaseId:如果配置了 databaseIdProvider,你就可以在动态代码中使用名为 “_databaseId” 的变量来为不同的数据库构建特定的语句。
根据不同数据库 执行不同操作
<select id="test_DataBaseId" resultType="users">
<if test="_databaseId=='oracle'">
select u_name,u_age from db_user
</if>
<if test="_databaseId=='mysql'">
select u_name,u_id from db_user
</if>
</select>
9、对于接口参数,映射文件的处理方式
1)单个参数
Mybatis不会做任何处理,获取的名称任意 均可得到值
2)多个参数
多个参数MyBatis底层封装为一个Map对象
insert into tb_user value(null,#{arg0},#{arg1})
insert into tb_user value(null,#{param1},#{param2})
key:param1 param2........
value:参数值
#{}从map中根据键取值
多个参数传入,不使用键param1等获取 使用注解@Param("u_id")Integer id,@Param("u_name")String uname
映射文件中:#{u_id} #{u_name}
key:使用@Param注解指定的值
value:传入的参数值
#{指定Key}取出对应的参数
3)多个参数封装到一个对象
根据属性名称取值
4)多个参数封装到Map
Map:
<insert id="addUser4" parameterType="hashmap">
insert into tb_user value(null,#{uname},#{upwd})
</insert>键为map.put()时的覆盖key名称
如果多个参数不在业务逻辑的数据类型中,没有对应POJO,可以将多个参数封装到map中
#{key} 取出Map中对应的值
3)List集合类型参数
一般插入多个 由foreach循环获取 处理并且 集合对象的属性获取按 对象.属性
4)指定获取参数的名称
@Param注解("定义的名称")
10、对于NULL类型的处理
Mybatis对所有的null都是映射到原生jdbc other类型
oracle不能识别 jdbc other
处理方式:
1、MyBatis-Config.xml设定
2、sql语句中 #{uImage,jdbcType=NULL}
11、MyBatis配置文件的基本配置标签
1)<properties resource="db.properties"></properties>
引入文件并且可以配数据库连接属性时,${uname}动态获取
2)用于对数据库的一些设置 name指定设置的参数 ,value指定参数取值
<settings>
<setting name="" value=""></setting>
</settings>
常见的参数配置:
jdbcTypeForNull 为不支持jbdb Other类型为NULL的数据库指定为NULL,
mapUnderscoreToCamelCase 设为true 将数据库表字段形如 ‘u_id’ 与实体类的uId对应 (开启驼峰命名)
cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
<!-- 开启全局 延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
3)类型别名 标签
<typeAliases>
<!--java类型取别名-->
<typeAlias type="com.ssm.vote.bean.User" alias="user"/>
<!--包下类型取别名 类名首字母小写-->
<pakcage name="com.ssm.vote.bean"/>
</typeAliases>
实体类 @Alias("别名") 优先于 包别名
12、缓存
13、结果映射 关系映射 一对多、多对一
resultMap标签:多表查询映射、自定义结果映射
1)一对一:type="user"包含一对一关系的实体类,property实体类属性,column表字段
<resultMap type="users" id="myUsers">
<id property="u_id" column="u_id"/>
<result property="u_age" column="u_age"/>
<result property="u_name" column="u_name"/>
<result property="userType.t_id" column="t_id"/>
<result property="userType.t_name" column="t_name"/>
</resultMap>
<select id="findUsers" parameterType="users" resultMap="myUsers">
select u_id,u_name,u_age,t.t_id,t_name from db_user u inner join db_type t on u.t_id=t.t_id where u_id=#{u_id}
</select>
2)association标签 关联元素 处理一对一 property="userType"为实体类的联合查询属性,javaType="userType"是属性类型
<!-- 一对一关系标签 -->
<resultMap type="users" id="myUsers2">
<id property="u_id" column="u_id"/>
<result property="u_age" column="u_age"/>
<result property="u_name" column="u_name"/>
<association property="userType" javaType="userType">
<id property="t_id" column="t_id"/>
<result property="t_name" column="t_name"/>
</association>
</resultMap>
3)一对多 collection关联 分步查询 将 多表查询 拆为两个分步单表sql
<resultMap type="userType" id="myUserType2">
<id column="t_id" property="t_id"/>
<result column="t_name" property="t_name"/>
<collection property="users" column="t_id" select="com.ssm.vote.dao.UserTypeMapper.findUserss">
</collection>
</resultMap>
<select id="findUserType2" resultMap="myUserType2">
select t_id,t_name from db_type where t_id=#{t_id}
</select>
<select id="findUserss" resultType="users">
select u_id,u_name,u_age from db_user where t_id=#{t_id}
</select>
14、分步查询
association:实现分步查询,(发送两个单表sql),property="userType" 表示实体类的属性 javaType="userType" 该属性的全路径类型名称
column="t_id" 该对象的查询参数 由第一次查询得出 select="com.ssm.vote.dao.UsersMapper.getT_id"映射的查询的接口方法
fetchType="lazy(eager)" 表示延迟加载 如果没有使用 association的属性 即不发送该接口方法的sql
<!-- 分步查询 -->
<resultMap type="users" id="myUsers3">
<id property="u_id" column="u_id"/>
<result property="u_age" column="u_age"/>
<result property="u_name" column="u_name"/>
<association property="userType" javaType="userType" column="t_id" select="com.ssm.vote.dao.UsersMapper.getT_id" >
</association>
</resultMap>
<select id="findUsers3" parameterType="users" resultMap="myUsers3">
select u_id,u_name,u_age,t_id from db_user where u_id=#{u_id}
</select>
<select id="getT_id" resultType="userType">
select t_id,t_name from db_type where t_id=#{t_id}
</select>
15、oracle的jdbc other类型问题与 MyBatis内oracle序列的使用