MyBatis框架,基础库框架
[TOC]
参考网站 mybatis中文文档 mybatis源码中文注释
MyBatis框架 1 MyBatis框架引言 1-1 MyBatis框架的基本概念 MyBatis是一个持久层框架,完成对数据库的访问(CRUD)
1-2 MyBatis框架与JDBC对比 jdbc访问和操作数据库存在的问题:
大量的代码冗余
手工处理ORM(麻烦)
没有对数据库进行优化(Cache)
解决JDBC访问和操作数据库存在 的问题,是对原有JDBC技术的封装。
1-3 MyBatis框架的核心编程思路 449
在原来的JDBC三层模型汇总,先进行书写DAO接口后实现DAO实现类,MyBatis的解决思路是使用mapper xml类型文件代替DAO实现类的功能。
2 第一个MyBatis程序的开发(HelloWorld) 2-1 环境搭建(OpenSource) i.Ibatis是MyBatis的前身,apache组织 ii.IBatis从3.0开始改名为MyBatis google code iii.MyBatis 属于GitHub
2-1-1 导入jar包
MyBatis的核心jar包
第三方依赖jar
相关数据库的驱动jar
2-1-2 引入配置文件 2-1-2-1 log4j.properties[可选] log4日志文件放置在src目录下
2-1-2-2 MyBatis-config.xml 建议放置在src目录下 配置的是MyBatis运行的相关参数
2-1-2-3 Mapper文件 实现DAO接口 位置建议xxxDao接口放在同一目录下
2-1-3 初始化配置 MyBatis-config.xml配置
oracle数据库配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "mybatis-3-config.dtd" > <configuration > <environments default ="oracle" > <environment id ="oracle" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="oracle.jdbc.OracleDriver" /> <property name ="url" value ="jdbc:oracle:thin:@localhost:1521:xe" /> <property name ="username" value ="hr" /> <property name ="password" value ="hr" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="com/baizhi/dao/UserMapper.xml" /> </mappers > </configuration >
< environments default=”oracle”> —- 默认环境 < environment id=”oracle”> —- 环境的唯一标识 < transactionManager type=”JDBC”> —- 采用JDBC的事务控制 < dataSource type=”POOLED”> —- MyBatis原生的连接池 < mapper resource=”com/baizhi/dao/UserMapper.xml” /> —- 注册Mapper文件
2-1-3-1 补充MyBatis-config中的配置信息 别名TypeAlias
实体的权限定名1 2 3 <typeAlias > <typeAlias type ="com.hibiscidai.entity.User" alias ="A" /> </typeAlias >
1 2 3 <select id ="selectByNameAndPassword" resultType ="A" > select * from t_user where username=#{username} and password=#{passowrd} </select >
配置内容参数化 问题:在mybatis-config文件中有经常需要修改的字符串相关(数据库相关) 解决方案:把在mybatis-config配置文件中经常需要修改的字符串信息提取到小配置文件中
i.读取小配置文件
1 2 3 <properties resource ="jdbc.properties" > </properties >
resource=”jdbc.properties” ——小配置文件存放路径
ii.${key}获取小配置文件中对应的值
1 2 3 4 5 6 <dataSource type ="POOLED" > <property name ="driver" value ="${driver}" /> <property name ="url" value ="${url}" /> <property name ="username" value ="${username}" / <property name ="password" value ="${password}" /> </dataSource >
1 2 3 4 driver = oracle.jdbc.OracleDriver url = jdbc:oracle:thin:@localhost :1521 :xe username = hr password = hr
2-2 MyBatis API 三个重要的类
2-2-1 Resources 读取mybaitis-fonfig配置文件,打开IO
2-2-2 SqlSessionFactory 通过SqlSessionFactory这个工厂创建SqlSession对象
2-2-3 SqlSession 作用:
根据程序员书写的Mapper文件,自动创建mapper文件对应的java类(DAO接口的实现类)
SqlSession内部封装了Connection对象
SqlSession控制事务
SqlSession.commit——Connection.commit SqlSession.rollback——Connection.rollback
注意:实战开发中,增删改需要控制事务 查询不需要控制事务
2-3 MyBatis 的开发步骤
建表
写实体
DAO接口
Mapper文件做DAO的实现
1 public User selectByID (Integer id) ;
1 2 3 <select id ="selectByID" parameterType ="int" resultType ="com.hibiscidai.entity.User" > select * from t_user where id=#{id} </select >
User —- resultType=”com.hibiscidai.entity.User” selectByID —- id=”selectByID” Integer id —- parameterType=”int”
1 2 3 <mappers > <mapper resource = "com/hibiscidai/dao/UserMapper.xml" /> </mappers >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void testMybatis () throws Exception { InputStream stream = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(stream); SqlSession sqlSession = sqlSessionFactory.openSession(); UserDAO userDAO = sqlSession.getMapper(UserDAO.class); User user = userDAO.selectByID(1 ); System.out.println(user); }
3 参数绑定 3-1 Mybaits代码中形参名与mapper文件中的#{}的名字没有必然联系 1 public User selectByID (Integer id) ;
1 2 3 <select id ="selectByID" parameterType ="int" resultType ="com.hibiscidai.entity.User" > select * from t_user where id=#{hibiscidai} </select >
Integer id —hibiscidai
3-2 Mapper文件中可以通过下标的形式,代表接口中的形参 1 public User selectByID (Integer id) ;
1 2 3 <select id ="selectByID" parameterType ="int" resultType ="com.hibiscidai.entity.User" > select * from t_user where id=#{0} </select >
Integer id —0
下标默认从0开始
3-3 多参数形式的查询解决方案 注意:在mybatis进行查询时,paramterType是可以省略的,不能随意指定#{},名字
3-3-1 可以通过下标的形式进行操作 1 public User selectByNameAndPassword (String username, String password) ;
1 2 3 <select id ="selectByNameAndPassword" resultTpe ="com.baizhi.entity.User" > select * from t_user where username=#{0} and password=#{1} </select >
3-3-2@Param注解进行参数绑定[建议] 注:
mybaits中消除xml大小写
1 public User selectByNameAndPassword (@Param("u") String username, @Param("p") String password) ;
1 2 3 <select id ="selectByNameAndPassword" resultType ="com.hibiscidai.entuty.User" > select * from t_user where username=#{u} and password=#{p} </select >
3-3-3 使用集合(map)进行传参[早期] 1 2 3 4 Map<String, String> map = new HashMap <String, String>(); map.put("username" , "hibiscidai" ); map.put("passowrd" , "123456" ); User user = userDAO.selectByNameAndPassword(map);
1 select * from t_user where username=#{username} and password=#{passowrd}
1 public User selectByNameAndPassword (Map<String, String> params) ;
4 MyBatis中CUD(增删改) 注意:在MyBatis应用的过程中,处理CUD时,必须要手工控制事务,否则操作不执行
1 2 sqlSession.commit(); sqlSession.rollback();
4-1 删除 1 public void delete (Integer id) ;
1 2 3 <delete id ="delete" > delete from t_user where id=#{id} </delete >
4-2 修改 1 public void update (User user) ;
1 2 3 4 5 User { id username password }
1 2 3 <update id ="update" > update t_user set username=#{username}, password=#{password} where id=#{id} </update >
4-3 插入 Sequence序列进行主键插入[Oracle]
1 public void insert (User user) ;
1 2 3 4 5 User { id = null username = hibiscidai passowrd = 123456 }
1 2 3 4 5 6 <insert id ="insert" > <selectKey keyProperty ="id" order ="BEFORE" resultType ="int" > select z.newxval from dual </selectKey > inset int t_user (id, username, password) values(#{id}, #{usename}, #{password}) </insert >
案例 serviceimpl层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public User regist (User user) { SqlSession session = MyBatisUtil.openSqlSession(); UserDAO ud = (UserDAO) session.getMapper(UserDAO.class); User u = null ; try { ud.insertSelective(user); u = ud.selectByEmail(user.getdEmail()); session.commit(); } catch (Exception e) { e.printStackTrace(); } finally { session.close(); } return u; }
注意从session获取Mapper执行后注意commit
5 MyBatisUtil工具类的封装 对于MyBatis三种类对象的分析
Resources类
特点:读取MyBatis-config配置文件 IO
建议:一次性通过IO读取所有的数据
SqlSessionFactory类
特点:创建SqlSession 重量级的资源 内存占用多 功能多
建议:每一个应用只创建一个 线程安全
SqlSession类
特点:清零及资源 不能被多线程共享
创建DAO接口的实现类(动态代理设计思想 动态字节码技术)
SqlSession内部封装Connnection 一个SqlSession对应一个Connection
事务控制
```SqlSession.rollback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 import java.io.IOException;import java.io.InputStream;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;public class mybatisutils { public static SqlSessionFactory sqlSessionFactory; public static ThreadLocal<SqlSession> tl = new ThreadLocal <SqlSession>(); static { InputStream stream = null ; try { stream = Resources.getResourceAsStream("mybatis-config.xml" ); sqlSessionFactory = new SqlSessionFactoryBuilder ().build(stream); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException ("读取配置文件失败" ); } finally { try { stream.close(); } catch (Exception e2) { e2.printStackTrace(); } } } public static SqlSession opSqlSession () { SqlSession sqlSession = tl.get(); if (null == sqlSession) { sqlSession = sqlSessionFactory.openSession(); tl.set(sqlSession); } return sqlSession; } public static void closeSqlSession () { SqlSession sqlSession = opSqlSession(); sqlSession.close(); tl.remove(); } public static void commit () { SqlSession sqlSession = opSqlSession(); sqlSession.commit(); closeSqlSession(); } public static void rollback () { SqlSession sqlSession = opSqlSession(); sqlSession.rollback(); closeSqlSession(); } public static Object getMapper (Class clazz) { SqlSession sqlSession = opSqlSession(); return sqlSession.getMapper(clazz); } }
6 ResultMap(结果映射,结果对应关系) 作用:解决了实体类与数据库中的表不匹配
6-1 定义ResultMap 1 2 3 4 5 <resultMap type ="Customer" id ="CustomerResultMap" > <id property ="id" column ="t_id" /> <result property ="username" column ="t_username" /> <result property ="password" column ="t_password" /> </resultMap >
< id >
标签表示对主键的处理< result >
标签表示对费主键的处理
property
— 代表实体的名字column
— 代表数据库中的列名
6-2 使用ResultMap 1 2 3 4 5 6 7 8 <resultMap type ="Customer" id ="CustomerResultMap" > <id property ="id" column ="t_id" /> <result property ="username" column ="t_username" /> <result property ="password" column ="t_password" /> </resultMap > <select id ="selectByID" resultType ="CustomerResultMap" > select * from t_customer where t_id=#{id} </select >
注意:如果在开发中,只解决列名不一致的问题,有简化的方式,起别名
1 2 3 4 5 6 <typeAliases > <typeAlias type ="com.baizhi.entity.Customer" alias ="Customer" /> </typeAliases > <select id ="selectByID" resultType ="Customer" > select t_id as id,t_username as username,t_password as password from t_customer where t_id=#{id} </select >
7 MyBatis框架进行多表操作 7-1 实体之间的关系分类 i.实体之间有关联关系(有 从属 has a)【重点】
a) 1 : 1 b) 1 : c) : * ii.实体之间继承关系(is a)
7-2 MyBatis中如何处理管理关系 7-2-1 entity处理 关系属性:把关系另一方作为本方属性进行存储
单向关系:只能从关系其中一方 找到关系的另一方
双向关系:从关系的双方都可以找到关系的另一方
级联查询:1 2 PersonDAO.query(id) ---> Person(passport) PassportDAO.query(id) ---> Passport(person)
看似是单表处理 实际完成多张表的操作
7-2-2 表 表中如何简历关联关系:外键
一对一 随便建
一对多 建在多的一方
多对多 建在第三张表中
表中关系的方向行:天生的双向关系
注意
父没有外键 先插入
子表没有外键 先删除
7-2-3 DAO接口 有几个DAO, 对应写几个DAO
7-2-4 Mapper文件处理 自定义结果映射
8 关联关系的实战开发 8-1 1:1关联关系 1 2 3 4 5 6 7 8 9 10 <resultMap type ="Person" id ="PersonResultMap" > <id column ="pid" property ="id" /> <result column ="pusername" property ="username" /> <result column ="page" property ="age" /> <association property ="passport" javaType ="Passport" > <id column ="sid" property ="id" /> <result column ="sserial" property ="serial" /> <result column ="splace" property ="place" /> </association > </resultMap >
8-2 1:*关联关系(重点) 例: 部门(Department)与职员(Employee)关系
1 2 3 4 5 6 Employee id username age salary department
1 2 3 4 5 Department id departmentname departmentnumber List<Employee> employees
t_employee
| id | usename | age | salary | did | | :—: | :—: | :—: | :—: | :—: | | 1 | hibiscidai | 18 | 10000| 1 | | 1 | laowang| 18 | 100| 1 |
t_department
| id | epartmentname | epartmentnumber | | :—: | :—: | :—: | | 1 | 研发部 | 1111 |
一对多关联关系,集合作为关系属性,需要对集合进行初始化操作。
8-3 : 关联关系(了解) 例: 学生(Student)与课程(Course)关系1 2 3 4 5 6 Student id studentnumber studentname age List<Course>
1 2 3 4 5 Course id coursename score List<Student>
t_student | 学生表
id
studentnumber
studentname
age
1
1111
hibiscidai
18
1
2222
hibiscizhang
28
1
3333
hibisciwang
38
t_sc | 多对多映射表
id
sid
cid
1
1
1
2
1
1
3
2
1
4
2
2
t_course | 课程表
id
coursename
score
1
java
3
2
oracle
2
8-4 关联关系总结 8-4-1 Entity 关系属性 a)一个对象 b)集合 进行初始化
8-4-2 Table外键 一对一 随便建 一对多 建在多的一方 多对多 建在第三张表中
8-4-3 Mapper文件 ResultMap 一个对象
1 <association property ="" javaType ="" >
多个对象
1 <collection property ="" oftype ="" >
9 动态SQL 作用:简化mapper文件的配置
9-1 Sql片段 1 2 3 4 5 6 7 8 9 <sql id ="selectAll" > select * from t_teacher </sql > <select id ="selectByID" resutlType ="Teacher" > <include refid ="selectAll" /> where id=#{id} </select > <select id ="selectByName" resultType ="Teacher" > <include refid ="selectAll" /> where teachername=#{name} </select >
9-2 where语句的动态Sql 作用:同样的表,根据不同列的内容查询,通过where的动态sql
TeacherDAO文件重构
未使用where
1 2 3 4 5 6 7 8 public Teacher selectByID (Integer id) ;public Teacher selectByName (String name) ;public Teacher selectByNumber (String number) ;public Teacher selectByIDAndName (@Param("id") Integer ID,@Param("name") String name) ;
使用where后
1 public Teacher selectByWhere (Integer id, String name, String number)
Mapper文件重构
未使用where
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <sql id ="selectAll" > select * from t_teacher </sql > <select id ="selectByID" resutlType ="Teacher" > <include refid ="selectAll" /> where id=#{id} </select > <select id ="selectByName" resultType ="Teacher" > <include refid ="selectAll" /> where teachername=#{name} </select > <select id ="selectByNumber" resultType ="Teacher" > <include refid ="selectAll" /> where teachernumber=#{number} </select > <select id ="selectByIDAndName" resultType ="Teacher" > <include refid ="selectAll" /> where id=#{id} and teachername=#{name} </select >
使用where后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <sql id ="selectAll" > select * from t_teacher </sql > <select id ="selectByWhere" resultType ="Teacher" > <include refid ="selectAll" /> <where > <if test ="id!=null" > id=#{id} </if > <if test ="name!=null" > and name=#{name} </if > <if test ="number!=null" > and number=#{number} </if > select * from t_teacher where id=#{id} select * from t_teacher where name=#{name} select * from t_teacher where number=#{number} select * from t_teacher where id=#{id} and name=#{name} </where > </select >
xml逻辑映射:
1 2 3 4 name=null, number=null where id=#{id} id=null, number=null where name=#{name} id=null, name=null where number=#{number} number=null where id=#{id} and number=#{number}
1 2 3 4 5 6 7 8 9 10 11 12 13 <select id ="selectByDynamic" resultType ="Teacher" > <include refid ="selectAll" /> <where > <if test ="id!=null" > id=#{id} </if > <if test ="teachername!=null" > and teachername=#{teachername} </if > <if test ="teachernumber!=null" > and teachernumber=#{teahcernumber} </if > </where >
注意:用where动态sql时候,多参数做参数绑定时,要与数据库中的列名保持一致。 如果起始条件为null则忽略and号
新的写法:
1 2 3 4 5 6 7 8 9 10 11 <trim prefix ="where" prefixOverrides ="and/or" > <if test ="id!=null" > id=#{id} </if > <if test ="teachername!=null" > and teachername=#{teachername} </if > <if test ="teachernumber!=null" > and teachernumber=#{teachernumber} </if > </trim >
prefix
忽略前缀
prefixOverrides
忽略前缀and或者or
9-3 修改操作的动态Sql 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <update id ="updateTeacher" > update t_teacher <set > <if test ="teachername!=null" > teachername=#{teachername}, </if > <if test ="teachernumber!=null" > teachernumber=#{teachernumber}, </if > <if test ="age!=null" > age=#{age} </if > </set > where id=#{id} </update >
新的写法
1 2 3 4 5 6 7 8 9 10 11 12 <trim prefix ="set" suffixOverrides ="," > <if test ="teachername!=null" > teachername=#{teachername}, </if > <if test ="teachernumber!=null" > teachernumber#={teachernumber}, </if > <if test ="age!=null" > age=#{age} </if > </trim > where id=#{id}
9-4 批量操作(批量删除,批量查询) 1 2 3 4 5 6 <select id ="selectByIDs" resyltType ="Teacher" > select * from t_teacher where id in <foreach collection ="array" open ="(" items ="ids" separator ="," close =")" > #{ids} </froeach > </select >
1 2 3 select * from t_teacher where id in <foreach collection ="list" open ="(" item ="ids" separator ="," close =")" > </foreach >
如果参数是list集合 collection属性值设置为list
10 MyBatis的缓存(Cache) 10-1 缓存简述
减少与数据库之间的频繁通信
内存中随机读写效率高于硬盘
内存造价高,内存物理上线不大 无法缓存海量数据
数据安全性差
原则: 缓存中存储的数据一定是经常需要查询的数据,而且不是经常需要修改的数据
10-2 缓存开启步骤 10-2-1 开启MyBatis的全局缓存 Mybatis-config.xml配置
1 2 3 4 <settings > <setting name ="cacheEnabled" value ="true" /> </setting >
10-2-2 设置需要存储在缓存中的数据 1 2 3 4 5 6 <cache > </cache > <select id ="selectByID" resultType ="Person" > select * from t_person where id=#{id} </select >
注意实体类起别名
10-2-3 放置在缓存中的实体对象都需要实现serializable接口 1 2 3 4 5 6 7 8 public class Person implements Serializable { private Integer id; private String username; private String password; private Integer age; public Integer getId () {} ... }
序列化目的:唤出策略(用少的数据写入硬盘中)
只有session关闭时,MyBatis才会把数据存储在缓存中
事务提交时(CUD),MyBatis会自动清空缓存
查询方法不需要控制,但是一定要关闭SQLsession
CUD必须要控制事务
单表查询建议采用MyBatis缓存
第三方缓存: eacache,redis,memcache