MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
总之,Mybatis对JDBC访问数据库的过程进行了封装,简化了JDBC代码,解决JDBC将结果集封装为Java对象的麻烦。
下图是MBatis架构图 (1)mybatis-config.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂
(2)基于SqlSessionFactory可以生成SqlSession对象
(3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。
(4)Executor是SqlSession底层的对象,用于执行SQL语句
(5)MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)
思考:在开始之前,思考下如何通过JDBC查询Emp表中的所有记录,并封装到一个List集合中返回。(演示:准备数据、导包、导入JDBC程序)
(1)使用JDBC访问数据库有大量重复代码(比如注册驱动、获取连接、获取传输器、释放资源等,执行一次SQL语句就需要连接一次数据库);
(2)JDBC自身没有连接池,会频繁的创建连接和关闭连接,效率低;
(3)SQL是写死在程序中,一旦修改SQL,需要对类重新编译;
(4)对查询SQL执行后返回的ResultSet对象,需要手动处理,有时会特别麻烦(未尝试过,不过会有这样的现象);
…
(1)Mybatis对JDBC对了封装,可以简化JDBC代码;
(2)Mybatis自身支持连接池(也可以配置其他的连接池),因此可以提高程序的效率;
(3)Mybatis是将SQL配置在mapper文件中,修改SQL只是修改配置文件,类不需要重新编译。 如果是简单语句可以通过注解加配置文件
(4)对查询SQL执行后返回的ResultSet对象,Mybatis会帮我们处理,转换成Java对象。 底层会根据相对应的POJO对象的getXxx()方法或者根据POJO对象的属性(数据库表的列名需与POJO对象的属性名一致)将返回的ResultSet对象封装到POJO对象中 …
总之,JDBC中所有的问题(代码繁琐、有太多重复代码、需要操作太多对象、释放资源、对结果的处理太麻烦等),在Mybatis框架中几乎都得到了解决!!
这个是通过配置xml文件来执行SQL语句的方式
在增删改查操作中,SQL语句中的值是写死在SQL语句中的,而在实际开发中,此处的值往往是用户提交过来的值,因此这里我们需要将SQL中写死的值替换为占位符。
在mybatis中占位符有两个,分别是 #{} 占位符 和 ${} 占位符:
#{}:相当于JDBC中的问号(?)占位符,是为SQL语句中的参数值进行占位,大部分情况下都是使用#{}占位符; 并且当#{}占位符是为字符串或者日期类型的值进行占位时,在参数值传过来替换占位符的同时,会进行转义处理(在字符串或日期类型的值的两边加上单引号) 例如:查询指定name的员工信息,SQL语句为: select * from emp where name=#{name}其实就等价于JDBC中:
select * from emp where name=?,如果传过来的参数值为:张三,那么最终执行的SQL语句为:
-- 在参数替换占位符的同时进行了转义处理(在值的两边加上了单引号) select * from emp where name='张三' ${}:是为SQL片段进行占位,将传过来的SQL片段直接拼接在${}占位符所在的位置,不会进行任何的转义处理。(由于是直接将参数拼接在SQL语句中,因此可能会引发SQL注入攻击问题) 那么如果我们在传递的时候不是一个参数值,而是一个SQL片段呢?例如:在查询时,我们想动态的传递查询的列:
select #{columns} from emp此时传递过来的应该是一个SQL片段,不同于上面的参数值,如果此时还用#{},也会像上面一样被转译处理:
select 'id,name,job' from emp这不是我们希望看到的!
如果不想让传过来的SQL片段被转译处理,而是直接拼接在SQL语句中,那么这里可以使用${},例如:
select ${columns} from emp拼接之后:
select id,name,job from emp使用哪种方式要看你实际SQL语句
<if>标签:是根据test属性中的布尔表达式的值,从而决定是否执行包含在其中的SQL片段。如果判断结果为true,则执行其中的SQL片段;如果结果为false,则不执行其中的SQL片段
<where>标签:用于对包含在其中的SQL片段进行检索,在需要时可以生成where关键字,并且在需要时会剔除多余的连接词(比如and或者or)
练习:根据薪资查询员工信息(if标签)
<if>标签:是根据test属性中的布尔表达式的值,从而决定是否执行包含在其中的SQL片段。如果判断结果为true,则执行其中的SQL片段;如果结果为false,则不执行其中的SQL片段在mapper文件中编写SQL语句:
<!-- 练习: 根据薪资查询员工信息 * 如果没有参数, 则不执行where子句, 默认查询所有员工: * select * from emp * 如果参数中只有minSal(即minSal不为null), 则: * ... where salary > minSal * 如果参数中只有maxSal(即maxSal不为null), 则: * ... where salary < maxSal * 如果参数有 minSal、maxSal(即minSal、maxSal不为null), 则: * ... where salary > minSal and salary < maxSal --> <select id="findAllBySal" resultType="com.tedu.pojo.Emp"> select * from emp where 1=1 <if test="minSal != null"> and salary>#{minSal} </if> <if test="maxSal != null"> and salary <![CDATA[ < ]]> #{maxSal} </if> </select>练习:根据薪资查询员工信息(where标签)
<where>标签:用于对包含在其中的SQL片段进行检索,在需要时可以生成where关键字,并且在需要时会剔除多余的连接词(比如and或者or) <!-- 练习: 根据薪资查询员工信息 * 如果没有参数, 则不执行where子句, 默认查询所有员工: * select * from emp * 如果参数中只有minSal(即minSal不为null), 则: * ... where salary > minSal * 如果参数中只有maxSal(即maxSal不为null), 则: * ... where salary < maxSal * 如果参数有 minSal、maxSal(即minSal、maxSal不为null), 则: * ... where salary > minSal and salary < maxSal --> <select id="findAllBySal" resultType="com.tedu.pojo.Emp"> select * from emp <where> <if test="minSal != null"> and salary>#{minSal} </if> <if test="maxSal != null"> and salary <![CDATA[ < ]]> #{maxSal} </if> </where> </select>foreach标签:可以对传过来的参数数组或集合进行遍历,以下是foreach标签上的各个属性介绍:
属性属性描述collection必需,值为遍历的集合类型,例如:如果参数只是一个数组或List集合,则collection的值为array或list;如果传的是多个参数,用map封装,collection则指定为map中的key。item必需,若collection为数组或List集合时,item表示其中的元素,若collection为map中的key,item表示map中value(集合或数组)中的元素open可选,表示遍历生成的SQL片段以什么开始,最常用的是左括号’(’close可选,表示遍历生成的SQL片段以什么结束,最常用的是右括号’)’separator可选,每次遍历后给生成的SQL片段后面指定间隔符练习: 根据员工的id批量删除员工信息 在mapper文件中编写SQL语句:
<!-- 练习14: 根据员工的id批量删除员工信息 delete from emp where id in (1,3,5,7) collection: 如果传的参数仅仅是一个数组或者List集合, collection可以指定为 array或list; 如果传的是多个参数,用map封装,collection则指定为map中的key open: 指定生成的SQL片段以什么符号开始 close: 指定生成的SQL片段以什么符号结束 item: 指定变量接收数组或集合中的元素 separator: 指定一个间隔符, 在将数组或集合中的每个元素拼接到SQL片段之后, 在后面拼接一个间隔符 --> <delete id="deleteByIds"> delete from emp where id in <foreach collection="array" open="(" item="id" separator="," close=")"> #{id} </foreach> </delete>