Mybatis
mybatis ORM框架
(1)和hibernate相比
1.hibernate功能完善 , mybatis稍欠缺,例如在缓存方面
2.hibernate hql方言的支持,可以在任意数据库上生成对应的sql语句,移植性更强
mybatis因为是编写sql语句,所以移植性较差
3.hibernate全自动化面向对象的编程,mybatis半自动化,面向sql编程
4.mybatis开发效率较高
(2)开发流程
在mapper.xml文件中编写sql语句,同时让mapper的namespace映射接口的路径
1.DAO层接口中定义方法,但是不写具体注解来实现
2.定义Maaper文件,文件中的语句的数量对应着接口的方法的个数,并且语句的id和
方法名相同
3.Mapper文件的namespace指向接口的路径
4.在核心配置中注册Mapper文件路径就可以
5.使用的时候还是getMapper(接口.class) 还是使用接口,符合开发的思想
(3)Mybatis在IDEA中的创建案例
1.IDEA先创建一个java项目,
2.导入依赖pom.xml,
3.创建java目录Mark为Sources Root,里面写java代码
4.main下同级创建resources目录Mark为Resources Root,里面存放配置文件。
mybatis.cfg.xml Mybatis的配置文件
jdbc.properties 连接池中数据库的配置
resources中创建mappers文件,里面存放XXXMapper.xml文件
5.test文件夹下为测试类
如图文件:
pom.xml中主要依赖:
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!-- JDBC JAR --> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>1.0</version> </dependency> </dependencies>
Mybatis的配置文件:mybatis-config.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 3 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 4 5 <configuration> 6 <!--读取属性文件--> 7 <properties resource="jdbc.properties"></properties> 8 <settings> 9 <setting name="logImpl" value="STDOUT_LOGGING" /> 10 <!--启用延迟加载--> 11 <setting name="lazyLoadingEnabled" value="true"/> 12 <!--cacheEnabled 启用二级缓存--> 13 <setting name="cacheEnabled" value="true"></setting> 14 </settings> 15 16 <!--别名--> 17 <typeAliases> 18 <!--单个类别名 19 <typeAlias type="com.seecen.Student" alias="student"></typeAlias> 20 --> 21 <!--该包下所有的类可以直接使用类名做为别名--> 22 <package name="com.seecen"/> 23 </typeAliases> 24 25 <!--配置环境--> 26 <environments default="development"> 27 <environment id="development"> 28 <!--jdbc事务--> 29 <transactionManager type="JDBC"/> 30 <!--支持连接池的方式--> 31 <dataSource type="POOLED"> 32 <property name="driver" value="${driver}"/> 33 <property name="url" value="${url}"/> 34 <property name="username" value="${username}"/> 35 <property name="password" value="${password}"/> 36 </dataSource> 37 </environment> 38 </environments> 39 40 <mappers> 41 <!--<mapper resource="mappers/studentMapper.xml"></mapper> 42 <!–需要给接口注册–> 43 <mapper class="com.seecen.StudentDao"></mapper>--> 44 45 <mapper resource="mappers/empMapper.xml"></mapper> 46 <mapper resource="mappers/deptMapper.xml"></mapper> 47 </mappers> 48 49 50 </configuration>
oracle数据库连接池的配置:jdbc.properties
url=jdbc:oracle:thin:@localhost:1521:orcl
driver=oracle.jdbc.driver.OracleDriver
username=sc1812
password=sc1812
编写XXXMapper.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 3 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 4 5 <!--指向接口的名称--> 6 <mapper namespace="com.seecen.EmpDao"> 7 8 <select id="listEmp" resultMap="empResultMap"> 9 select * from emp 10 </select> 11 <!-- 12 解决属性名和字段名不同的情况 13 用来复杂的对象关系映射的查询 14 id 唯一 15 type 就是指这个resultMap的结果类型 16 --> 17 <resultMap id="empResultMap" type="Emp"> 18 <id property="empNo" column="EMPNO"></id> 19 <result property="ename" column="ENAME"/> 20 <result property="job" column="JOB"/> 21 <result property="hiredate" column="HIREDATE"/> 22 <result property="sal" column="SAL"/> 23 <result property="comm" column="COMM"/> 24 <result property="mgr" column="MGR"/> 25 26 <!-- 27 在关系映射中,所关联的另一张表的数据被封装在对象中,而这个对象 28 的属性都写在这里 29 property 30 column 指关联表在当前表中的外键 31 javaType 指关联的这个对象的类型--> 32 <!--<association property="dept" column="DEPTNO" javaType="Dept"> 33 <id property="deptNo" column="DEPTNO" ></id> 34 <result property="dname" column="DNAME"></result> 35 <result property="loc" column="LOC"></result> 36 </association>--> 37 38 <!--使用另一条查询语句的结果来使用 39 DEPTNO 这个时候还有另一个用途,用来把该列的值传递给对应的select语句做为参数 40 --> 41 <association property="dept" column="DEPTNO" 42 select="com.seecen.DeptDao.getDept"> 43 </association> 44 </resultMap> 45 46 <select id="listEmpByDept" resultMap="empResultMap"> 47 select * from emp where deptno = #{param1} 48 </select> 49 50 <select id="getEmp" resultType="Emp"> 51 select * from emp where empno = #{param1} or sal = #{param2} 52 </select> 53 54 <insert id="insertEmp"> 55 <![CDATA[ 56 insert into emp values(#{id},#{name},#{job},#{mgr},to_date(#{hiredate},'yyyy-mm-dd'),#{sal},#{comm},#{deptno}) 57 ]]> 58 </insert> 59 60 <!--模糊查询--> 61 <select id="listEmpByName" resultMap="empResultMap"> 62 select * from emp 63 <!-- <where> 64 <if test="arg0!='%%'"> 65 and ename like #{param1} 66 </if> 67 <if test="arg1!=0"> 68 and deptno = #{param2} 69 </if> 70 </where>--> 71 <trim prefix="where" prefixOverrides="and | or"> 72 <if test="arg0!='%%'"> 73 and ename like #{param1} 74 </if> 75 <if test="arg1!=0"> 76 and deptno = #{param2} 77 </if> 78 </trim> 79 </select> 80 81 <update id="updateEmp" parameterType="Emp"> 82 update emp 83 <set> 84 <!--<if test="ename!='' and ename!=null"> 85 ENAME = #{ename}, 86 </if> 87 <if test="job!='' and job!=null"> 88 JOB = #{job}, 89 </if>--> 90 </set> 91 where EMPNO = #{empNo} 92 </update> 93 94 <select id="listEmpIn" resultMap="empResultMap"> 95 select * from emp where empno in 96 <!-- 97 collection:表示要遍历的数据的类型,array,list等 98 item : 表示每次迭代的一个数据的别名 99 --> 100 <foreach collection="array" item="id" open="(" close=")" 101 separator="," > 102 #{id} 103 </foreach> 104 </select> 105 106 <insert id="batchInsert" parameterType="list"> 107 insert all 108 <foreach collection="list" item="e" separator=" "> 109 into EMP (EMPNO,ENAME,JOB,MGR,SAL,COMM,HIREDATE,DEPTNO) 110 values 111 ( 112 #{e.empNo}, 113 #{e.ename}, 114 #{e.job}, 115 #{e.mgr}, 116 #{e.sal}, 117 #{e.comm}, 118 to_date(#{e.hiredate},'yyyy-MM-dd'), 119 #{e.dept.deptNo} 120 ) 121 </foreach> 122 select 1 from dual 123 </insert> 124 125 </mapper>
根据数据库编写实体类
测试类:
1 package com.seecen; 2 3 import org.apache.ibatis.io.Resources; 4 import org.apache.ibatis.session.SqlSession; 5 import org.apache.ibatis.session.SqlSessionFactory; 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 8 import java.io.IOException; 9 import java.io.InputStream; 10 import java.util.List; 11 12 /** 13 * Hello world! 14 * 15 */ 16 public class App 17 { 18 public static void main( String[] args ) throws IOException { 19 20 //读取核心配置文件 21 InputStream inputStream = Resources.getResourceAsStream("mybatis.cfg.xml"); 22 23 SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream); 24 25 SqlSession sqlSession = sqlSessionFactory.openSession(); 26 //mapper的namespace+语句的id 27 List<Student> list = sqlSession.selectList("com.seecen.StudentMapper.listStudent"); 28 29 for (Student student : list) { 30 System.out.println(student.getStuName()); 31 } 32 33 34 35 } 36 }
一、mybatis整体架构设计分为三层:API接口层、数据处理层、基础支持层。
- API接口层:提供外部使用接口的API,通过提供的API操作数据库。接口层收到调用参数后就会将这些参数作为入参数调用数据处理层来完成具体的数据处理。
- 数据处理层:接收到接口层的参数,具体负责对SQL的查找,解析,执行和执行结果的映射处理,完成对数据库的操作。
- 基础支持层:负责最基础且公用的功能支持,包括数据库连接管理、事务管理、配置加载和缓存处理。这些功能抽取出来作为基础功能,为上层的数据处理层提供最基础的支撑。
二、mybatis整个调用执行过程:
- 加载配置并初始化:即mybatis主配置文件,mapper配置文件及注解配置。其中将SQL配置的信息加载为一个个MapperStatement对象(传入参数映射配置、执行的SQL语句、结果映射配置)。
- 接收调用请求:接收到传入的参数和需要执行的SQL的ID,将请求传递给下层的数据处理层进行处理。
- 处理操作请求:执行器Executor处理接收到接口层传递的SQL的ID和传入参数,根据ID查找对应的MapperStatement,解析MapperStatement对象,得到需要执行的SQL语句并注入传入的参数。获取到数据库连接,将最终的SQL语句到数据库执行,并得到结果。根据MapperStatement对象中的结果映射配置对得到的结果进行转换处理,得到最终的结果。最后释放资源并返回结果到上层。
精讲#{}和${}的区别是什么?
#{}是预编译处理,${}是字符串替换。
(1)mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值。
(2)mybatis在处理${}时,就是把${}替换成变量的值。
(3)使用#{}可以有效的防止SQL注入,提高系统安全性。原因在于:预编译机制。预编译完成之后,SQL的结构已经固定,即便用户输入非法参数,也不会对SQL的结构产生影响,从而避免了潜在的安全风险。
(4)预编译是提前对SQL语句进行预编译,而其后注入的参数将不会再进行SQL编译。我们知道,SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译成了恶意的执行操作。而预编译机制则可以很好的防止SQL注入。
最后,补充一点:
$符号一般用来当作占位符,常使用Linux脚本的人应该对此有更深的体会吧。例如:$1,$2等等表示输入参数的占位符。知道了这点就能很容易区分$和#,从而不容易记错了。