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 findAll();
//------------------------------------------------------------------
@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 &amp;&amp; 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标签可以在标签所在的位置输出一个where关键字,而且可以将后面多余的and或者or关键字去除,格式如下:

§<!-- 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标签相似,主要是在标签所在的位置输出一个set关键字,而且还可以去除内容结尾无关的逗号,格式如下:

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转义字符
<	&lt;
>	&gt;
&	&amp;
'	&apos;
"	&quot;
空格&nbsp;

②采用<![CDATA[]]>说明,将此内容不进行解析
<if test="">
	and e_salary <![CDATA[<]]> 50000.0 只对小于号不解析
</if>	

二、获取自动递增主键值(MyBatis03_02)
在插入操作时,返回自动递增的主键值

· MySQL(数据库支持自动递增)

insert into t_dept values(#{deptno},#{dname})

标签指定自动递增属性设置后,MyBatis会在插入操作后将自动递增生成的主键值给keyProperty指定的属性赋值

· 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表达式显示数据

posted @ 2020-11-09 23:15  D•U•S•Tべ  阅读(100)  评论(0)    收藏  举报