MyBatis 开源的数据持久化层框架
实体类与SQL语句之间建立映射关系
一:MyBatis前身是IBatis,本是Apache的一个开源的项目,
基于SQL语法,简单易学 ,是耦合度降低,方便程序调式
二:搭建Mybatis的开发步骤:
a:下载mybatis-3.3.3.jar包并导入工程
b.编写MyBatis核心配置文件(configuration.xml)
c.创建实体类-POJO
d.DAO层-SQL映射文件(mapper.xml)
e.创建测试类
读取全局配置文件mybatis-config.xml
创建SqlSessionFactory对象,读取配置文件
创建SqlSession对象
调用mapper文件进行数据操作
我的大配置(全局配置里)
<configuration> <properties resource="database.properties"/> <environments default="development"> <settings> <setting name="LogImpl" value="LOG4J"> </setting> </settings> <environment id="development"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="${driver}"></property> <property name="url" value="${url}"></property> <property name="username" value="${user}"></property> <property name="userpwd" value="${password}"></property> </dataSource> </environment> </environments>
<mappers>
<mapper resource="cn/smbms/dao/user/UserMapper" </mappers> </properties> </configuration>
小配置:
在dao层:
<mapper namespace="cn.smbms.dao.user.UserMapper"> <!--查询用户表的记录数--> <select id="count" resultType="int"> select count(1) as count from login </select> </mapper>
在userMapperTest: public class UserMapperTest{ private Logger logger=Logger.getLogger(UserMapperTest.class); @Test public void test(){ string resource="mybatis-config.xml" int count=0; SqlSession sqlsession=null; try{ //1.获取mybatis-config.xml输入流 Inputstream is=Resources.getResourceAsStream(resource) //2.创建SqlSessionFactory对象,完成对配置文件的读取 SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is). //3.创建SqlSession sqlSession=factory.openSession(); //4.调用mapper文件来对数据文件进行操作,必须将mapper文件引入到 count=sqlSession.selectOne("cn.smbms.dao.user.UserMapp"); logger.debug("UserMapper"+count); }catch(IoException e){ e.printStackTrace(); }finally{ sqlSession.close(); }
优缺点:
优点:
与JDBC相比,减少了50%以上的代码量
小巧易学
提供XML标签,支持编写动态SQL
提供映射标签
缺点:
数据库移植性差
编写工作量大
MyBatis专注于SQL本身,是一个足够灵活得DAO层解决方案
适用于性能要求较高或者需求多变的互联网项目
四:::::基本要素:::::
三个基本要素:
1. 核心接口和类:
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
2. mybatis-config.xml
3.mapper.xml SQL映射文件
共用的Util工具类
MyBatisUtil:
public class MyBatisUtil{ private static SqlSessionFactory factory; static{ try{ InputStream is=Resources.getResourceAsStream(""); factory=new SqlSessionFactoryBuilder().bulid(is); }catch(IOException e){ e.printStackTrace(); } } public static SqlSession createSqlSession(){ return factory.openSession(false); } public static void closeSqlSession(SqlSession sql){ if(null!=sqlSession){ sqlSession.close(); } } }
核心配置文件:
environments元素:
1.表示MyBatis的多套运行环境,将SQL映射到多个不同的数据上。
2.子元素节点:environment,但是必须指定其中一个默认运行环境(通过default指定)
transactionManager-事物管理器
<transactionManager type="[JDBC|MANAGED]"/> ======>>MANAGED(托管)
3.dataSource元素使用基本的JDBC数据源接口来配置JDBC连接对象的资源
三种内建的数据源类型:
<dataSource type="[UNPOOLED|POOLED|JNDI]"/>
复杂对象:map
所有对象 === 增删改查 ===一级缓存二级缓存
public interface StudentDao { //查询所有信息 public List<Student> selectStudent() throws Exception; //主键id查询 public Student getById(int ID); //添加学生 public int addStudent(Student stu) throws Exception; //修改学生 public int upStudent(Student stu) throws Exception; //删除学生 public int delStudent(int ID) throws Exception; //模糊条件查询:学生姓名是豆,并且年龄在10岁以上的 public List<Student> ConditionStudent(Student stu) throws Exception; //findStudent<map>集合 多条件查询1 public List<Student> findStudent(Map<String,Object> map); //按照索引号查询 多条件查询2 public List<Student> ConditionParameters(String StuName,int StuAge) ; //智能标签if 检测用户是否录入学生姓名和年龄 public List<Student> findByIf(Student stu) throws Exception; //智能标签choose 检测用户是否录入学生姓名和年龄 public List<Student> findByChoose(Student stu) throws Exception; //智能标签foreach 检测In(或者) public List<Student> findByForeach(int[] arg) throws Exception; //智能标签foreach List<Integer> 检测In(或者) public List<Student> ForeachList(List<Integer> list) throws Exception; //智能标签foreach List<Student> 检测In(或者) public List<Student> ForeachListStudent(List<Student> list) throws Exception; //if-set public int getset(Student stu); //01.查询指定老师教的学生 多对多 public RTeacher getStudentByTid(int id); //根据父分类编号,检索该父类编号对应的所有子分类的集合==============递归方法 public List<Category> getChildrenByPid(int pid); }
小配置文件里:
<mapper namespace="cn.zixin.dao.StudentDao"> <!--二级缓存第二步--> <cache/> <!--SQL片段--> <sql id="columns"> ID,StuName,StuAge,StuTime </sql> <!--查询所有的resultMap的用法:--> <resultMap id="studentmap" type="Student"> <id column="ID" property="ID"></id> </resultMap> <select id="selectStudentS" resultMap="studentmap"> select <include refid="columns"></include> from student </select> <!--查询所有--> <select id="selectStudent" resultType="Student"> select * from student </select> <!--通过id查询--> <select id="getById" resultType="Student"> select * from student where ID=#{ID} </select> <!--添加学生--> <insert id="addStudent"> INSERT INTO student(StuName,StuAge,StuTime) VALUE (#{StuName},#{StuAge},#{StuTime}) </insert> <!--修改学生--> <update id="upStudent"> UPDATE student SET StuName=#{StuName} WHERE ID=#{ID} </update> <!--删除学生--> <delete id="delStudent"> DELETE from student where ID=#{ID} </delete> <!--模糊查询学生--> <!--SELECT * from student WHERE StuName like concat('%',#{StuName},'%') AND StuAge>#{StuAge}--> <!--可以被SQL注入到 SELECT * from student WHERE StuName like '%${StuName}%' AND StuAge>#{StuAge}--> <select id="ConditionStudent" resultType="Student"> SELECT * from student WHERE StuName like '%' #{StuName} '%' AND StuAge>#{StuAge} </select> <!-- MAP集合查询 多条件查询--> <select id="findStudent" resultType="Student"> select * from student where StuName like '%' #{StuName} '%' AND StuAge>#{StuAge} </select> <!-- <resultMap id="Student" type="Student"> <id property="id" column="id"></id> <result column="StuName" property="StuName"></result> <result property="StuAge" column="StuAge"></result> </resultMap> --> <!--根据索引查询--> <select id="ConditionParameters" resultType="Student"> SELECT * FROM student WHERE StuName like '%' #{0} '%' and StuAge >#{1} </select> <!--智能标签if 检测用户是否录入学生姓名和年龄--> <select id="findByIf" resultType="Student"> SELECT * FROM student <where> <if test="StuName!=null"> <!--用户录入的姓名字段--> AND StuName LIKE '%'#{StuName}'%' </if> <if test="StuAge!=null"> AND StuAge>#{StuAge} </if> </where> </select> <!--智能标签Choose 检测用户是否录入学生姓名和年龄--> <select id="findByChoose" resultType="Student"> SELECT * FROM student <where> <choose> <when test="StuName!=null"> AND StuName LIKE '%'#{StuName}'%' </when> <when test="StuAge!=null"> AND StuAge>#{StuAge} </when> <otherwise> AND 1=2 </otherwise> </choose> </where> </select> <!--智能标签Foreach Array 检测In(或者)--> <select id="findByForeach" resultType="Student"> SELECT * FROM student <where> <if test="array.length>0"> ID IN <foreach collection="array" open="(" close=")" separator="," item="aD"> #{aD} </foreach> </if> </where> </select> <!--智能标签Foreach List<Integer> 检测In(或者)--> <select id="ForeachList" resultType="Student"> SELECT * FROM student <where> <if test="list.size>0"> ID IN <foreach collection="list" open="(" close=")" separator="," item="ID"> #{ID} </foreach> </if> </where> </select> <!--智能标签Foreach List<student> 检测In(或者)--> <select id="ForeachListStudent" resultType="Student"> SELECT * FROM student <where> <if test="list.size>0"> ID IN <foreach collection="list" open="(" close=")" separator="," item="stu"> #{stu.ID} </foreach> </if> </where> </select> <!--if-set--> <update id="getset" > UPDATE student <set> <if test="StuName!=null" >StuName=#{StuName},</if> <if test="StuAge!=null">StuAge=#{StuAge},</if> </set> WHERE ID=#{ID} </update> <!--查询指定老师教的学生 多对多--> <resultMap id="stuMapper" type="RTeacher"> <id column="tid" property="tid"></id> <result column="tname" property="tname"></result> <collection property="stus" ofType="RStudent"> <id column="sid" property="sid"></id> <result column="sname" property="sname"></result> </collection> </resultMap> <select id="getStudentByTid" resultMap="stuMapper" parameterType="RTeacher"> SELECT sname,sid,tid,tname FROM student2,teacher,teacher_student WHERE student2.sid=teacher_student.studentid AND teacher.tid=teacher_student.teacherid AND tid=#{tid} </select>
测试类里:
//查询 @Test public void findsStudent() { List<Student> list = myBatis.getSession().selectList("selectStudentS"); for (Student item : list) { System.out.println(item.getStuName()); } } //id查询 @Test public void getById() { /* //映射关系第一种Class<T>类型 Class<StudentText> aClass = StudentText.class; //映射关系第二种 try { Class<StudentText> name = ( Class<StudentText>)Class.forName("cn.zixin.test.StudentText"); } catch (ClassNotFoundException e) { e.printStackTrace(); }*/ //映射关系第三种 getMapper SqlSession session = myBatis.getSession(); StudentDao dao = session.getMapper(StudentDao.class); Student byId = dao.getById(1); System.out.println(byId.getStuName()); //Student stu= session.selectOne("getById",1); // System.out.println(stu.getStuName()); session.commit(); session.close(); } //增加 @Test public void addStudent() throws Exception { SqlSession session = myBatis.getSession(); StudentDao dao = session.getMapper(StudentDao.class); Student stu = new Student(); stu.setStuName("豆豆"); stu.setStuAge(29); stu.setStuTime(new Date()); dao.addStudent(stu); session.commit(); //增删改 手动提交事务 System.out.println("ok"); session.close(); } //修改 @Test public void upStudent() throws Exception { SqlSession session = myBatis.getSession(); StudentDao dao = session.getMapper(StudentDao.class); Student stu = new Student(); stu.setStuName("豆豆"); stu.setID(2); dao.upStudent(stu); session.commit(); //增删改 手动提交事务 System.out.println("ok"); session.close(); } //删除 @Test public void delStudent() throws Exception { SqlSession session = myBatis.getSession(); StudentDao dao = session.getMapper(StudentDao.class); dao.delStudent(2); session.commit(); //增删改 手动提交事务 System.out.println("ok"); session.close(); } //模糊查询 @Test public void ConditionStudent() throws Exception { SqlSession session = myBatis.getSession(); StudentDao dao = session.getMapper(StudentDao.class); Student stu = new Student(); stu.setStuName("豆"); stu.setStuAge(30); List<Student> list = dao.ConditionStudent(stu); for (Student item : list) { System.out.println(item.getStuName()); } session.commit(); //增删改 手动提交事务 System.out.println("ok"); session.close(); } //findStudent<map>集合 多条件查询 @Test public void mapsStudent() throws Exception { SqlSession session = myBatis.getSession(); StudentDao dao = session.getMapper(StudentDao.class); Map<String,Object> map=new HashMap<String,Object>(); map.put("StuName","豆"); map.put("StuAge",20); List<Student> list = dao.findStudent(map); for (Student item : list) { System.out.println(item.getStuName()); } System.out.println("ok"); session.close(); } //按照索引号查询 @Test public void ConditionParameter() { String StuName = "豆"; int StuAge = 20; List<Student> list = myBatis.getSession().getMapper(StudentDao.class).ConditionParameters(StuName,StuAge); for (Student stu : list) { System.out.println(stu.getStuName()); } } @Test //智能标签if public void findByIf() throws Exception { Student stu = new Student(); stu.setStuName( "豆"); stu.setStuAge( 29); List<Student> list = myBatis.getSession().getMapper(StudentDao.class).findByIf(stu); for (Student item : list) { System.out.println(item.getStuName()); } System.out.println("ok"); } @Test //智能标签choose public void findBychoose() throws Exception { Student stu = new Student(); stu.setStuName( "豆"); stu.setStuAge( 29); List<Student> list = myBatis.getSession().getMapper(StudentDao.class).findByChoose(stu); for (Student item : list) { System.out.println(item.getStuName()); } System.out.println("ok"); } @Test //智能标签foreach array public void findByForeach() throws Exception { int[] arg={2,5}; List<Student> list = myBatis.getSession().getMapper(StudentDao.class).findByForeach(arg); for (Student item : list) { System.out.println(item.getStuName()); } System.out.println("ok"); } @Test //智能标签foreach List<Integer> public void foreachList() throws Exception { List<Integer> lists=new ArrayList<Integer>(); lists.add(2); lists.add(5); List<Student> list = myBatis.getSession().getMapper(StudentDao.class).ForeachList(lists); for (Student item : list) { System.out.println(item.getStuName()); } System.out.println("ok"); } @Test //智能标签foreach List<Student> public void foreachListStudent() throws Exception { List<Student> lists=new ArrayList<Student>(); Student s1=new Student(); s1.setID(2); Student s2=new Student(); s2.setID(5); lists.add(s1); lists.add(s2); List<Student> list = myBatis.getSession().getMapper(StudentDao.class).ForeachListStudent(lists); for (Student item : list) { System.out.println(item.getStuName()); } System.out.println("ok"); } @Test // 多表联查 一对多 单条SQL public void selectOne() throws Exception { Dept dept = myBatis.getSession().getMapper(IdeptDao.class).getEmpsByDeptNO(1); System.out.println(dept.getDeptname()); for (Emp emp:dept.getEmps()){ System.out.println(emp.getEmpname()); } System.out.println("ok"); } @Test // 多表联查 一对多 多条SQL public void selectmoen() throws Exception { Dept dept = myBatis.getSession().getMapper(IdeptDao.class).getEmpsByDeptNoMutilSQL(1); System.out.println(dept.getDeptname()); for (Emp emp:dept.getEmps()){ System.out.println(emp.getEmpname()); } System.out.println("ok"); } @Test // 多对一 根据员工的编号,获取员工姓名 和 部门名称 单条SQL public void selectManyToOne() throws Exception { Emp emp = myBatis.getSession().getMapper(IdeptDao.class).getEmpByEmpNo(1); System.out.println(emp.getEmpname()); System.out.println(emp.getDept().getDeptname()); System.out.println("ok"); } @Test // 多对一 根据员工的编号,获取员工姓名 和 部门名称 多条SQL public void selectMany() throws Exception { Emp emp = myBatis.getSession().getMapper(IdeptDao.class).getEmpByEmpNoMutilSQL(1); System.out.println(emp.getEmpname()); System.out.println(emp.getDept().getDeptname()); System.out.println("ok"); } @Test //if-set public void testIsSet() throws Exception { Student stu=new Student(); stu.setStuName("欣欣"); stu.setStuAge(10); stu.setID(1); int i = myBatis.getSession().getMapper(StudentDao.class).getset(stu); System.out.println(i); } @Test //多对多 查询指定老师教的学生 public void testManyToMany() throws Exception { RTeacher teacher = myBatis.getSession().getMapper(StudentDao.class).getStudentByTid(1); System.out.println(teacher.getTname()); for (RStudent stu:teacher.getStus()){ System.out.println(stu.getSname()); } System.out.println("ok"); } @Test //自连接测试=======递归 public void testSelf() throws Exception { List<Category> list= myBatis.getSession().getMapper(StudentDao.class).getChildrenByPid(0); for (Category item : list) { System.out.println(item); } System.out.println("ok"); } @Test //一级缓存 存在性的证明 public void testOneLevelCache() throws Exception { List<Student> list = myBatis.getSession().getMapper(StudentDao.class).selectStudent(); for (Student item : list) { System.out.println(item); } System.out.println("============一级缓存"); List<Student> list1 = myBatis.getSession().getMapper(StudentDao.class).selectStudent(); for (Student item : list1) { System.out.println(item); } System.out.println("ok"); } @Test //增删改对一级缓存的影响 public void testUpdateHashSomeThinngToOneLevelCache() throws Exception { Student Stu=new Student(); Stu.setID(6); Stu.setStuName("件件"); Stu.setStuAge(12); int i = myBatis.getSession().getMapper(StudentDao.class).addStudent(Stu); System.out.println(i); System.out.println("============一级缓存"); System.out.println("ok"); }
一对多 === 多对多
接口类里:
public interface IdeptDao { //一对多 单条SQL实现方法 public Dept getEmpsByDeptNO(int deptno); //一对多 多条SQL实现方法 public Dept getEmpsByDeptNoMutilSQL(int deptno); //多对一 单条SQL 根据员工的编号,获取员工姓名 和 部门名称 public Emp getEmpByEmpNo(int empno); //多对一 多条SQL 根据员工的编号,获取员工姓名 和 部门名称 public Emp getEmpByEmpNoMutilSQL(int empno); }
在我的小配置里:
<mapper namespace="cn.zixin.dao.IdeptDao"> <!--一对多 单条SQL实现方法--> <resultMap id="deptMapper" type="Dept"> <id column="deptno" property="deptno"></id> <result column="deptname" property="deptname"></result> <collection property="emps" ofType="Emp"> <id property="empno" column="empno"></id> <result column="empname" property="empname"></result> </collection> </resultMap> <select id="getEmpsByDeptNO" resultMap="deptMapper"> select dept.deptno,deptname,empno,empname from dept,emp where dept.deptno=emp.deptno and dept.deptno=#{deptno} </select> <!--一对多 多条SQL实现方法--> <resultMap id="deptMappers" type="Dept"> <id column="deptno" property="deptno"></id> <result column="deptname" property="deptname"></result> <collection property="emps" ofType="Emp" select="deptBy" column="deptno"></collection> </resultMap> <select id="deptBy" resultType="Emp"> SELECT * FROM emp WHERE deptno=#{deptno} </select> <select id="getEmpsByDeptNoMutilSQL" resultMap="deptMappers"> select deptno,deptname from dept where deptno=#{deptno} </select> <!--多对一 根据员工的编号,获取员工姓名 和 部门名称 单条SQL--> <resultMap id="empMapper" type="Emp"> <id column="empno" property="empno"></id> <result column="empname" property="empname"></result> <association property="dept" javaType="Dept"> <id column="deptno" property="deptno"></id> <result column="deptname" property="deptname"></result> </association> </resultMap> <select id="getEmpByEmpNo" resultMap="empMapper"> select dept.deptno,deptname,empno,empname from dept,emp where dept.deptno=emp.deptno and empno=#{empno} </select> <!-- 多对一 多条SQL 根据员工的编号,获取员工姓名 和 部门名称--> <resultMap id="empMutiMapper" type="Emp"> <id column="empno" property="empno"></id> <result column="empname" property="empname"></result> <association property="dept" javaType="Dept" select="selectDeptByDeptNo" column="deptno"> </association> </resultMap> <select id="selectDeptByDeptNo" resultType="Dept"> SELECT * from Dept where deptno=#{deptno} </select> <select id="getEmpByEmpNoMutilSQL" resultMap="empMutiMapper"> select deptno,empno,empname from emp where empno=#{empno} </select> </mapper>
注解:所有的测试类里都有所有的接口测试
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
iBATIS一词来源于"internet"和"abatis"的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)
我们把Mybatis的功能架构分为三层:
(1)API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
(2)数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
(3)基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
MyBatis 最强大的特性之一就是它的动态语句功能。如果您以前有使用JDBC或者类似框架的
经历,您就会明白把SQL语句条件连接在一起是多么的痛苦,要确保不能忘记空格或者不要在
columns列后面省略一个逗号等。动态语句能够完全解决掉这些痛苦。
尽管与动态SQL一起工作不是在开一个party,但是MyBatis确实能通过在任何映射SQL语句中
使用强大的动态SQL来改进这些状况。
动态SQL元素对于任何使用过JSTL或者类似于XML之类的文本处理器的人来说,都是非常熟悉
的。在上一版本中,需要了解和学习非常多的元素,但在MyBatis 3 中有了许多的改进,现在只
剩下差不多二分之一的元素。MyBatis使用了基于强大的OGNL表达式来消除了大部分元素。