MyBatis笔记
MyBatis第一天
1.什么是MyBatis
MyBatis最早源自Apache基金会的一个开源项目iBatis,2010年项目由Apache software foundation迁移
到Google Code,改名MyBatis
MyBatis是支持普通的SQL查询,存储过程和高级映射的优秀持久层框架,其使用简单的xml配置和注解配置
定义映射关系,将实体类对象映射成数据库记录
MyBatis工作原理
1)加载配置
MyBatis将SQL的映射加载为一个个的MappedStatement对象(包括传入的参数的映射配置,执行的SQL语
句,结果映射配置),将其存储在内存中
2)SQL解析
当API接口层收到调用请求时,会接受到传入SQL的ID和传入的参数对象(可以是Map,实体类或者基本数据类型),MyBatis会根据SQL的ID找到对应的MappedStatement,然后根据传入的参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数
3)SQL执行
将最终得到的SQL语句和参数拿到数据库进行执行,得到执行结果
4)结果映射
将操作数据库的结果按照结果映射配置进行转换,可以转换为Map,实体类或者基本数据类型,将转换结果返回
MyBatis框架API
SqlSessionFactoryBuilder
此组件负责根据MyBatis主配置文件构建SqlSessionFactoryBuilder
SqlSessionFactory
每一个MyBatis应用程序都以一个SqlSessionFactory对象为核心,此组件负责创建SqlSession对象
SqlSession
此组件包含所有执行SQL语句操作的方法,用于执行已经映射的SQL语句
MyBatis配置文件
①SqlMapConfig.xml(1个)
主配置文件,用于指定数据库连接信息和框架信息
②SqlMapper.xml(N个)
映射文件,用于定义SQL语句的映射信息
2.MyBatis基本操作
1)搭建MyBatis技术环境
为工程添加MyBatis的开发包和数据库驱动包,src下添加MyBatis的主配置文件SqlMapConfig.xml
配置SqlMapConfig.xml,指定数据库连接参数和框架参数,利用MyBatis提供的API,获取
SqlSession对象
2)获取SqlSession对象
String path = "主配置文件URL";
Reader reader = Resources.getResourceAsReader(path);
//构建SqlSessionFactory对象
SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();
SqlSessionFactory ssf = ssfb.build(reader);
//构建SqlSession对象
SqlSession ss = ssf.openSession();
3)利用SqlSession对象实现CRUD操作
增加(Create),读取查询(Retrieve),更新(Update),删除(Dedele)
·根据数据表编写实体类
·编写SqlMapper.xml映射文件,定义SQL操作和映射信息
·获取SqlSession对象,执行增删改查操作
·提交事务(DML)
·释放SqlSession对象资源
解决字段名与实体类属性名不一致的问题
注意:
不一致问题,如果结果集的字段名和实体类的属性名全部不一致,且在结果映射时定义为resultType,则不会创建实体类对象,但是如果只是部分不一致,则会创建实体对象并且自动关联属性名和字段名一致的属性
解决方式:
①通过在查询的SQL语句中定义字段名的别名,将字段名的别名和实体类的属性名保持一致
<select id="findAll" resultType="com.xms.entity.Dept">
select deptno as deptNo,dname as dName from t_dept
</select>
②通过<resultMap>来映射字段名和实体类属性名的一一对应关系,来自MyBatis提供的解决方式
==================================================================================
MyBatis第二天
一、优化MyBatis配置文件中的配置
1.连接数据库的配置
·第一种方式:
<environments default="develop">
<environment id="develop">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<!-- 引用上面定义的属性 -->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/xms/entity/mapper/DeptMapper.xml"/>
</mappers>
·第二种方式:(推荐)
<!-- 引入外部属性资源文件 -->
src下定义db.properties文件
<properties resource="db.properties"></properties>
<environments default="develop">
<environment id="develop">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<!-- 引用上面定义的属性 -->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
2.为类定义别名,简化映射文件中的引用
问题:在映射文件中引用实体类时,需要指定实体类的全类名(包名+类名)
resultType="com.xms.entity.Dept"
parameterType="com.xms.entity.Dept"
解决方法:
<!-- 指定类型别名 -->
<typeAliases>
<!--
<typeAlias type="com.xms.entity.Dept" alias="_Dept"/>
<typeAlias type="java.lang.Integer" alias="int"/>
<typeAlias type="com.xms.entity.Emp" alias="Emp"/>
-->
或
<!-- 指定类型别名包(批量),别名为类名 -->
<package name="com.xms.entity"/>
</typeAliases>
二、返回Map类型的查询结果
案例:
根据员工号查询员工信息,同时查询员工所在的部门信息
sql:select e.,d. from t_emp as e join t_dept d on e.e_deptno=d.d_id where e.e_id=1001;
三、Mapper映射接口(推荐)
Mapper映射接口是开发者创建用于绑定映射语句的接口,映射接口的实例对象可以从SqlSession对象获取
注意:
映射文件中namespace的值必须与对应Mapper接口的名称一致
映射文件中SQL的id必须与对应Mapper接口中方法名一致
四、注解方式实现CRUD(不推荐,适用于简单基本的增删改查)
@Select(/*value = */ "select * from t_emp")
@Results({@Result(column="e_id",property="eId"),
@Result(column="e_name",property="eName"),
@Result(column="e_salary",property="eSalary"),
@Result(column="e_bouns",property="eBouns"),
@Result(column="e_hiredate",property="eHiredate"),
@Result(column="e_deptno",property="eDeptno")})
List
//------------------------------------------------------------------
@Select("select * from t_emp where e_id=#{empno}")
@Results({@Result(column="e_id",property="eId"),
@Result(column="e_name",property="eName"),
@Result(column="e_salary",property="eSalary"),
@Result(column="e_bouns",property="eBouns"),
@Result(column="e_hiredate",property="eHiredate"),
@Result(column="e_deptno",property="eDeptno")})
Emp findById(@Param("empno")int id);//如果此处用@Param注解,SQL语句的#{empno}值就不能随便写;此处也可以不写注解
//------------------------------------------------------------------
@Insert("insert into t_emp values(#{eId},#{eName},#{eSalary},#{eBouns},#{eHiredate},#{eDeptno})")
void save(Emp emp);
//------------------------------------------------------------------
@Update("update t_emp set e_name=#{eName},e_salary=#{eSalary},e_bouns=#{eBouns},e_hiredate=#{eHiredate},e_deptno=#{eDeptno} where e_id=#{eId}")
void update(Emp emp);
//------------------------------------------------------------------
@Delete("delete from t_emp where e_id=#{eId}")
void delete(int id);
补充:mybatis中取变量值
#{}与${}
1.都是取变量的值
2.#{}在取值时,Sql语句中变量的值会替换成?(预编译),
${}直接替换成变量的值(非预编译),因此#{}处理是安全的,即可以防止SQL注入,且是预编译
3.${}方式一般用于传入数据库对象,例如:表名、字段名
select * from emp where id=#{id}
select * from emp where id=${id}
如果id参数的值是1001,则分别解析为
#{}->select * from emp where id=?
${}->select * from emp where id=1001
如果参数是String类型
"'id=1001'or'1=1'"
${}->select * from emp where id='id=1001'or'1=1' 永真式
什么时候用${} ?
order by id->
==================================================================================
MyBatis第三天(/MyBatis03_01)
一、MyBatis动态SQL
动态SQL是MyBatis框架中特性之一,在一些组合查询页面需要根据用户输入的条件不同生成不同的SQL查询语句,在JDBC或其他相似框架中需要在代码中拼接SQL语句,容易出错,MyBatis动态SQL可以解决这种问题
动态SQL标签与JSTL标签相似,它允许在xml中构建不同的SQL语句,常用SQL标签如下:
判断标签:if,choose(when,otherwise)
关键字 :where,set,trim
循环标签:foreach
·if
if标签是简单条件判断逻辑,满足指定条件时追加if标签内的Sql语句,不满足时不追加,格式如下:
if标签最常见的使用在where子句部分,根据不同的情况追加不同的SQL语句
§<!-- List<Emp> findEmpOne(Condition condition) -->
<select id="findEmpOne" resultMap="baseResultMap" parameterType="Condition">
select * from t_emp
<if test="name!=null && name.trim().length()>0">
where e_name=#{name}
</if>
</select>
·choose
choose标签的作用相当于Java的switch语句,基本上跟JSTL中choose的作用和用法是一致的,通常与when和otherwise搭配使用,格式如下:
§<!-- List<Emp> findEmpTwo(Condition condition) -->
<select id="findEmpTwo" parameterType="Condition" resultMap="baseResultMap">
select * from t_emp
<if test="salary!=null">
<choose>
<when test="salary>50000">
where e_salary>#{salary}
</when>
<when test="salary>40000">
where e_salary>#{salary}
</when>
<otherwise>
where e_salary>40000
</otherwise>
</choose>
</if>
</select>
·where
where标签可以在
§<!-- List<Emp> findEmpThree(Condition condition) -->
<select id="findEmpThree" parameterType="Condition" resultMap="baseResultMap">
select * from t_emp
<where>
<if test="name!=null">
e_name=#{name}
</if>
<if test="deptno!=null">
and e_deptno=#{deptno}
</if>
<if test="salary!=null">
or e_salary>#{salary}
</if>
</where>
</select>
·set
set标签主要是用在更新操作时,它的主要功能和where标签相似,主要是在
update emp
e_name=#{name}
e_salary=#{salary}
e_deptno=#{deptno}
where e_id=#{id}
§<!-- void updateOne(Emp emp) -->
<update id="updateOne" parameterType="Emp">
update t_emp
<set>
<if test="name!=null">
e_name=#{name},
</if>
<if test="salary!=null">
e_salary=#{salary},
</if>
<if test="deptno!=null">
e_deptno=#{deptno}
</if>
</set>
<if test="id!=null">
where e_id=#{id}
</if>
</update>
trim标签主要功能如下:
①可以在包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix
②可以把包含内容首部的某些内容过滤,即忽略,也可以把尾部的某些内容过滤,对应的属性是prefixOverrides和suffixOverrides
·
......
§<!-- List<Emp> findEmpFour(Condition condition) trim标签替代where标签-->
<select id="findEmpFour" parameterType="Condition" resultMap="baseResultMap">
select * from t_emp
<trim prefix="where" prefixOverrides="and|or">
<if test="name!=null">
e_name=#{name}
</if>
<if test="deptno!=null">
and e_deptno=#{deptno}
</if>
<if test="salary!=null">
or e_salary>#{salary}
</if>
</trim>
</select>
·
......
§<!-- void updateTwo(Emp emp) trim标签替代set标签-->
<update id="updateTwo" parameterType="Emp">
update t_emp
<trim prefix="set" suffixOverrides=",">
<if test="name!=null">
e_name=#{name},
</if>
<if test="salary!=null">
e_salary=#{salary},
</if>
<if test="deptno!=null">
e_deptno=#{deptno}
</if>
</trim>
<if test="id!=null">
where e_id=#{id}
</if>
</update>
·foreach
foreach标签实现循环逻辑,可以进行一个集合或数组的迭代,主要用在构建IN条件中,格式如下:
select * from t_emp where e_id in(1001,1003,1005);
§<!-- List<Emp> findById(Condition condition) -->
<select id="findById" parameterType="Condition" resultMap="baseResultMap">
select * from t_emp where e_id in
<foreach collection="empnos" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
foreach标签它允许指定一个集合,声明集合项和索引变量,变量可以用在标签体内,它允许指定开放和关闭的字符串,在迭代项之间放置分隔符
· 批量插入
§
insert into t_emp values
(#{emp.id},#{emp.name},#{emp.salary},#{emp.bouns},#{emp.hiredate},#{emp.deptno})
·bind
bind标签可以从 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文
select * from t_emp
where e_name like '%三%';
<select * from t_emp where e_name like concat ("%",#{name},"%")
注意:Oracle数据库中concat函数有且仅有2个参数,即需要嵌套调用
concat(concat("%",#{name}),"%")
§<select id="findByName" parameterType="Condition" resultMap="baseResultMap">
<bind name="nameLike" value="'%' + name + '%'" />
select * from t_emp where e_name like #{nameLike}
</select>
补充:
在xml文件中处理特殊符号
①采用xml转义字符
< <
> >
& &
' '
" "
空格
②采用<![CDATA[]]>说明,将此内容不进行解析
<if test="">
and e_salary <![CDATA[<]]> 50000.0 只对小于号不解析
</if>
二、获取自动递增主键值(MyBatis03_02)
在插入操作时,返回自动递增的主键值
· MySQL(数据库支持自动递增)
insert into t_dept values(#{deptno},#{dname})
在
· Oracle(数据库不支持自动递增,需要采用序列生成主键值)
create sequence dept_sequence start with 1 increment by1
<insert id="" parameterType="Dept">
<selectKey keyProperty="deptno">
resultType="integer"
select dept_sequence.nextval from dual
</selectKey>
insert into t_dept values(dept_sequence.currval,#{dname})
</insert>
在insert标签指定<selectKey>设置,MyBatis会在插入操作前先执行<selectKey>获取主键值的sql,然后再执行插入的sql
========================================================================================
MyBatis第四天
一、MyBatis关联映射(需要关联查询时使用,分析查询时是一对一还是一对多关系)
MyBatis的关联映射有两种不同的实现形式:
①嵌套查询:通过执行另一个SQL映射语句来返回关联数据(查询两次)
②嵌套结果查询:执行一个表关联查询SQL,然后将查询结果映射成关联对象(查询一次)
1.一对一映射
构建数据库:
create table t_teacher(
t_id int(4) primary key auto_increment,t_name varchar(10) not null);
create table t_class(
c_id int(2) primary key auto_increment,c_name varchar(20),teacher_id int(4));
alter table t_class add constraint fk_teacher_id foreign key(teacher_id)
references t_teacher(t_id);
insert into t_teacher(t_name) values("罗永浩");
insert into t_teacher(t_name) values("王阳明");
insert into t_class(c_name,teacher_id) values("三年二班",2);
insert into t_class(c_name,teacher_id) values("五年六班",1);
2.一对多映射
构建数据库:
create table t_student(
s_id int(4) primary key auto_increment,
s_name varchar(10) not null
);
create table t_course(
c_id int(4) primary key auto_increment,
c_name varchar(10) not null
);
create table student_course(
student_id int(4),
course_id int(4)
);
insert into t_student(s_name) values('陈一'),('陈二'),('陈三'),('陈四');
insert into t_course(c_name) values('语文'),('数学'),('英语');
insert into student_course values(1,1),(1,3),(2,1),(2,2),(2,3),(3,2),(3,3),(4,1),(4,2);
需求:查询学生信息同时查询学生选择的课程信息。
select s.*,c.* from t_student s join student_course sc
on s.s_id=sc.student_id
join t_course c on sc.course_id=c.c_id
where s.s_id=1;
二、MyBatis Generator
简称MBG,是一个专门为MyBatis框架使用者制定的代码生成器,可以快速根据数据库表生成对应的映射文件,接口,以及Bean实体类,支持基本的增删改查以及QBC(Query By Criteria:"面向对象"的一种检索方式)风格的条件查询,但是表连接,存储过程等复杂的SQL查询的定义需要手动编写
官方文档地址:
http://www.mybatis.org/generator
官方工程地址:
https://github.com/mybatis/generator/release
·generatorConfig.xml配置:
<!-- jdbcConnection:指定连接数据库的数据源 -->
<jdbcConnection connectionURL="jdbc:mysql:///test" driverClass="com.mysql.jdbc.Driver" password="1234" userId="root" />
<!-- javaModelGenerator:指定实体类生成对应的包及工程 -->
<javaModelGenerator targetPackage="com.xms.entity" targetProject=".\src" />
<!-- sqlMapGenerator:指定映射文件生成对应的包及工程 -->
<sqlMapGenerator targetPackage="com.xms.entity.mapper" targetProject=".\src" />
<!-- javaClientGenerator:指定映射接口生成对应的包及工程 -->
<javaClientGenerator targetPackage="com.xms.dao" targetProject=".\src" type="XMLMAPPER" />
<!-- table:指定代码生成对应的表 -->
<table tableName="t_emp" domainObjectName="Emp">
<!-- 指定数据库生成的表字段名和实体类中的属性名 -->
<columnOverride column="e_id" property="id" />
<columnOverride column="e_name" property="name" />
<columnOverride column="e_salary" property="salary" />
<columnOverride column="e_bouns" property="bouns" />
<columnOverride column="e_hiredate" property="hiredate" />
<columnOverride column="e_deptno" property="deptno" />
</table>
单元测试后自动生成代码:
@Test
public void test1() throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
========================================================================================
MyBatis第五天
一、MyBatis缓存(/MyBatis05_01)
MyBatis与其他持久层框架一样,支持一级缓存和二级缓存
一级缓存:基于PerpetualCache和HashMap本地缓存,其存储作用域为Session,当Session clear或close,此时Session中的缓存cache就将清空,一级缓存默认是开启的
二级缓存:与一级缓存机制相同,默认采用PerpetualCache和HashMap存储,不同在于其存储作用域为映射文件Mapper(Namespace),且可自定义存储源,如EhCache
对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespace)进行增删改C/U/D操作,默认此作用域下所有SELECT中的缓存都被clear
二级缓存补充说明:
①二级缓存需要手动开启(在映射文件中指定<cache/>)
②二级缓存中的缓存对象必须可序列化,即实体类必须实现Serializable接口
③映射文件中的select语句将会被缓存
④映射文件中insert,update,delete语句会刷新缓存
⑤缓存会根据指定时间间隔来刷新
⑥缓存会存储1024个对象
⑦缓存会使用Least Recently Used(LRU)算法来回收
<cache
eviction="" 回收策略
flushInterval="" 自动刷新时间
size="" 指定缓存对象个数
readOnly=""> 指定只读/读写
</cache>
二、Pagehelper分页插件(/MyBatis05_02)
官方工程地址:
https://github.com/pagehelper/MyBatis-PageHelper
①导包
②在SqlMapConfig.xml中配置
<!-- PageHelper拦截器插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
三、Spring与MyBatis整合(/MyBatis05_03)
Spring与MyBatis整合需要引入一个mybatis-spring.jar整合包,此整合包由MyBatis框架提供,此整合包提供以下与整合相关的API组件:
·SqlSessionFactoryBean
为整合应用提供SqlSession对象
·MapperFactoryBean(单个、批量)
根据指定的Mapper接口生成对应的实例对象
SqlSessionFactoryBean在applicationContext.xml中配置:
<bean id="" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定连接资源 -->
<!-- 指定映射文件 -->
</bean>
MapperFactoryBean的配置方式(单个注入):
<bean id="" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!-- 负责给映射接口实现实例对象 -->
<property name="mapperInterface" value="com.xms.dao.EmpMapper"/>
<property name="sqlSessionFactory" ref=""/>
</bean>
导包:
ioc 5
jdbc 2
aop 1
mybatis 1
mybatis-spring 1
mysql 1
dbcp 3
MapperScannerConfigurer的配置方式(批量扫描):
根据指定包批量扫描Mapper接口,生成对应的MapperFactoryBean
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定批量扫描包路径-->
<property name="basePackage" value=""/>
<!--指定sqlSessionFactory-->
<property name="sqlSessionFactory" ref=""/>
注意:sqlSessionFactory属性可以不用指定,会以Autowired方式自动注入
</bean>
如果指定的包下并不完全是我们定义的Mapper接口,此时可以用MapperScannerConfigurer的属性缩小注册范围,一个annotationClass,一个markerInterface
annotationClass:用于指定一个注解标记,当指定了此注解标记时,MapperScannerConfigurer将只注册使用此标记的接口
markerInterface:用于指定一个接口,当指定了此接口时,MapperScannerConfigurer将只注册继承自此接口的接口
四、Spring+SpringMVC+MyBatis(Emp的CRUD)
1.创建工程,搭建Spring,SpringMVC,MyBatis技术环境
创建一个web工程
添加MyBatis相关技术环境 添加jar包
引入数据库驱动包
引入DBCP连接池
引入MyBatis开发包
引入MyBatis与Spring整合开发包
添加Spring相关技术环境 添加jar包
引入Spring ioc,web,webmvc,jdbc,tx,aop开发包
在src下添加applicationContext.xml配置文件
在web.xml中配置DispatcherServlet控制器
在web.xml中配置中文乱码过滤器CharacterEncodingFilter
2.基于MyBatis实现DAO组件
根据数据表编写实体类
编写Mapper映射接口
在applicationContext.xml中定义SqlSessionFactoryBean组件
在applicationContext.xml中定义MapperScannerConfigurer(批量扫描Mapper接口)
3.编写和配置Spring,SpringMVC主要组件
编写Controller和请求处理方法
配置mvc:annotation-driver/支持@RequestMapping
配置Controller
开启注解扫描,将Controller等组件扫描到容器中
在请求处理方法上使用@RequestMapping指定对应请求
配置视图解析器ViewResolve
4.编写JSP视图组件,利用JSTL标签和EL表达式显示数据

浙公网安备 33010602011771号