1.数据库的环境切换
2.注解方式
## 推荐使用xml
a.将sql语句写在接口的方法前面
b.将接口的全类名写入到<mapper>,让mybatis知道sql语句此时是存储在接口中的。
注意:注解和XML都支持批量引入
<mappers>
<!--以下可以将com.itt.mapper包中的注解接口和xml
全部一次性引入-->
<package name="com.itt.mapper"/>
</mappers>
3.增删改的返回问题
- 返回值 可以是void ,Integer,Long,Boolean,只需要在接口中改返回值就可以了!
4.事务提交方式
- 手动提交:
SqlSession session = sessionFactory.openSession();
session.commit();//执行完commit时,手动提交 事务
- 自动提交 :每一个dml语句自动提交
SqlSession session = sessionFactory.openSession(true);
5.参数问题
目前将多个参数封装到一个javabean对象(pojo),然后使用该对象传递
-
a.传入多个参数时,不用在mapper.xml中编写parameterType
异常提示:
-
stuNo不能使用,使用的是:【arg3,arg2,arg1,arg0,param3,param2,param1】
<insert id="insertEmpInfo"> insert into empinfo(id,name,age,job,phone) values (#{arg0},#{arg1},#{arg2},#{arg3},#{arg4}) </insert>
-
b. 命名参数的方式
可以在接口中通过@Param("")来指定sql中参数的名字
void insertEmpInfo(@Param("sId") String id, @Param("sName") String name, @Param("sAge") String age, @Param("sJob") String job, @Param("sPhone") String phone);
<insert id="insertEmpInfo"> insert into empinfo(id,name,age,job,phone) values (#{sId},#{sName},#{sAge},#{sJob},#{sPhone}) </insert>
-
c. 综合使用的情况
//一个是简单类型 ,一个是对象类型 void insertEmpInfo(@Param("sId") String id,@Param("empInfo") EmpInfo empInfo);
<insert id="insertEmpInfo"> insert into empinfo(id,name,age,job,phone) values (#{sId},#{empInfo.name},#{empInfo.age},#{empInfo.job},#{empInfo.phone}) </insert>
6.增加null
oracle:如果插入的 字段是null,提示错误:Other 而不是gnull
mysql:如果插入的字段是null,可以正常执行(没有约束)
原因:
各个数据库在Mybatis中对各种数据类型的默认值不一致。
mybatis中,jdbcTypeForNull(如果是null),则默认值OTHER。
在mysql中,mybatis将Other当做NULL来处理了,但是oracle不行。
解决:
oracle:null -> OTHER 手工告诉oracle:other -> null
a. 当某个数据类型oracle无法处理进,告诉它用默认值null 来处理
//使用#{empInfo.name,jdbcType=null}这个就可以了
<insert id="insertEmpInfo">
insert into empinfo(id,name,age,job,phone)
values (#{sId},#{empInfo.name,jdbcType=null},#{empInfo.age},#{empInfo.job},#{empInfo.phone})
</insert>
b. 配置mybatis全局配置文件conf.xml
<settings>
<setting name="jdbcTypeForNull" value="NUll"/>
</settings>
7.返回值为HashMap的情况
- 注意:在mysql中@MapKey("id")字段为小写
- 在oracle中为全大写
- map:
- key:id value:Student
- 程序根据select的返回值,知道map的value就是EmpInfo,根据@MapKey("id")知道Map的key是id
@MapKey("id")
HashMap<String,EmpInfo> queryAllEmp();
<select id="queryAllEmp" resultType="HashMap">
select * from empinfo
</select>
8.ResultMap:字段和属性名的相应
- column指的是数据库中的列名
- property指的是类中的名字
<select id="queryAllEmpins" resultType="HashMap"
resultMap="EmpInoMap">
select * from empinfo
</select>
<resultMap id="EmpInoMap" type="empInfo">
<id column="eid" property="id"/>
<result column="ename" property="name"/>
<result column="eage" property="age"/>
<result column="ejob" property="job"/>
<result column="ephone" property="phone"/>
</resultMap>
9.别名问题
<!--设置单个/多个别名-->
<typeAliases>
<!--单个别名(别名 忽略大小写)-->
<!--<typeAlias type="com.itt.entity.Student" alias="student"/>-->
<!--批量定义别名,以下会自动将该包中的所有类 批量定义别名:别名就是类名(不带包名的类名)-->
<package name="com.itt.entity"/>
</typeAliases>
- 当这个包下的子包 与Student重名时,必须使用注解的方式重新命名
@Alias("myempinfo")
public class EmpInfo {
}
10.处理where子句后面的and的三种方式
- trim标签可以去掉后面的 and
- <trim>可以处理拼接sql中【开头或结尾】第一个and
<select id="queryByINP" parameterType="EmpInfo" resultType="EmpInfo">
select * from empinfo where
<trim>
<if test="id != null and id != 0">
id = #{id} and
</if>
<if test="name != null and name != ''">
name like '%${name}%' and
</if>
<if test="phone != null and phone != ''">
phone = #{phone} and
</if>
</trim>
</select>
- prefix="where":在整个语句中加where
- prefix="set":在整个语句中加set,可用于更新
- prefixOverrides="and":智能处理前面的and
- suffixOverrides="and":智能处理后面的and
- suffixOverrides=",":智能处理后面的,常用于更新
<trim prefix="where" prefixOverrides="and">
<if test="id != null and id != 0">
and id = #{id}
</if>
<if test="name != null and name != ''">
and name like '%${name}%'
</if>
<if test="phone != null and phone != ''">
and phone = #{phone}
</if>
</trim>
- <where>标签可以去掉前面的and
<select id="queryByINP" parameterType="EmpInfo" resultType="EmpInfo">
select * from empinfo
<where>
<if test="id != null and id != 0">
and id = #{id}
</if>
<if test="name != null and name != ''">
and name like '%${name}%'
</if>
<if test="phone != null and phone != ''">
and phone = #{phone}
</if>
</where>
</select>
- 直接 在where后面加:1 = 1
<select id="queryByINP" parameterType="EmpInfo" resultType="EmpInfo">
select * from empinfo where 1 = 1
<if test="id != null and id != 0">
and id = #{id}
</if>
<if test="name != null and name != ''">
and name like '%${name}%'
</if>
<if test="phone != null and phone != ''">
and phone = #{phone}
</if>
</select>
11.内置参数
- _paramter:代表Mybatis的输入参数
<select id="queryByINP" parameterType="EmpInfo" resultType="EmpInfo">
select * from empinfo
<trim prefix="where" prefixOverrides="and">
<if test="id != null and id != 0">
and id = #{id}
</if>
<if test="name != null and name != ''">
and ename like '%${name}%'
</if>
//_parameter替代parameterType这个输入的对象
<if test="_parameter.phone != null and _parameter.phone != ''">
and phone = #{_parameter.phone}
</if>
</trim>
</select>
- _databaseId:代表当前数据库的名字
12.模糊查询三种方式
12.1
- ${}原样输出
stuName like '%${stuName}%'
-
{}自动拼接' ':可以防止SQL注入
12.2 传值时,直接 传 %x%
student.setStuName("%s%");
stuName like #{stuName}
12.3 bind参数
<bind name="_queryName" value="'%'+name+'%'"/>
<if test="name != null and name != ''">
and name like #{_queryName}
</if>
I:\MyBatisIdea\MyBatisGenerator\src\main\java
13.逆向工程
1.导入依赖
2.xml模板文件(修改生成路径、表名)
3.根据java模板类一键生成
- 根据学生表->学生类、学生Mapper接口、studentMapper.xml
4.如何使用
* 增加Mybatis配置文件 conf.xml
- 对于like模糊查询,逆向工程需要在传值时 写入%x%
逆向工程的实例:使用的是StudentExample
- 测试类
@Test
public void queryAllEmpById() throws Exception{
//Connection - SqlSession操作myBatis
//config.xml -> reader
Reader reader = Resources.getResourceAsReader("conf.xml");
//reader ->SqlSession
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = sessionFactory.openSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
StudentExample example = new StudentExample();
StudentExample.Criteria criteria = example.createCriteria();
criteria.andStunameLike("%d%");
StudentExample example1 = new StudentExample();
StudentExample.Criteria criteria1 = example1.createCriteria();
//模糊查询
criteria1.andStunoEqualTo(10);
criteria1.andStunameLike("%k%");
//使用exampl整合的方式实现or操作
example.or(criteria1);
//Example中的Criteria:为查询的条件
List<Student> students = mapper.selectByExample(example);
System.out.println(students);
session.close();
}
14.MyBatis架构和源码解析
-
Mybatis源码的几个主要部件
MyBatis中步骤:
- 1.获取SqlSessionFactory对象
- 2.获取SqlSession对象
- 3.获取xxxMapper对象(代理接口 中的方法、mapper.xml中的<select>标签)
- 4.执行标签中定义的SQL语句
1.获取SqlSessionFactory对象
- parse解析器
-
通过Configuration标签设置了properties、typeAliases、environments等
-
通过Configuration标签设置了properties、typeAliases、environments等
-
Mybatis将所有的配置信息存放到了Configuration configuration对象中
-
mapperElement的过程
-
mapperElement的过程
-
<select id="",resultType="",parameterType="">等属性是通过
parseStatementNode()这个方法解析的
-
Mybatis会将xxxMapper.xml文件解析成MappedStatement对象
即parseStatementNode对象就是xxxMapper文件中的标签
MapperStatement -》存在于Configuration中
environment -》存在于Configuration中
-
所有的配置信息、增删改标签全部存在于Configuration中
SqlSessionFactory对象—》DefaultSqlSessionFactory—》Configuration—》所有的配置信息
2.获取SqlSession对象(Executor为执行器)
-
configuration.newExecutor(tx, execType);-》默认类型为simpleExecutor
- 并且根据不同的类型execType,产生不同的Executor,并对执行器进行拦截操作:
executor = (Executor) interceptorChain.pluginAll(executor);
作用:以后如果我们要给MyBatis写自己的插件,就可以通过拦截器实现:
-
下图就是使用拦截器一次次增强执行器Executor,从而使Executor有更强大的功能!
返回的是:
DefaultSqlSession(configuration, executor, 事务问题);SqlSession ->openSession()--->openSessionFromDataSource() -->DefaultSqlSession对象
-
执行的流程
SqlSession -> DefaultSqlSession对象 -> 执行SQL
插件开发:
1.写插件
2.把插件放入到拦截器中插件
select * from student --》拦截器
目标对象target的包装后的产物 --->metaObject.getValue("可以从target中获取")
通过打印语句,可知,target就是 RoutingStatementHandler
----------》
metaObject.getValue("可以从RoutingStatementHandler中获取")
可以从RoutingStatementHandler获得:getBoundSql,getParameterHandler
------->--->metaObject.getValue("parameterHandler")
- metaObject.getValue("parameterHandler.parameterObject")//xxxMapper.xml中的语句中的参数值
- metaObject.getValue("parameterHandler.boundSql")//xxxMapper.xml中sql的语句