参考网站
mybatis中文文档
mybatis源码中文注释
**
MyBatis框架
**
1 MyBatis框架引言
1-1 MyBatis框架的基本概念
MyBatis是一个持久层框架,完成对数据库的访问(CRUD)
1-2 MyBatis框架与JDBC对比
jdbc访问和操作数据库存在的问题:
i.大量的代码冗余
ii.手工处理ORM(麻烦)
iii.没有对数据库进行优化(Cache)
解决JDBC访问和操作数据库存在 的问题,是对原有JDBC技术的封装。
1-3 MyBatis框架的核心编程思路
在原来的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数据库配置
<?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
实体的权限定名
<typeAlias>
<typeAlias type="com.hibiscidai.entity.User" alias="A" />
</typeAlias>
<select id="selectByNameAndPassword" resultType="A">
select * from t_user where username=#{username} and password=#{passowrd}
</select>
配置内容参数化
问题:在mybatis-config文件中有经常需要修改的字符串相关(数据库相关)
解决方案:把在mybatis-config配置文件中经常需要修改的字符串信息提取到小配置文件中
i.读取小配置文件
<!-- 读取小配置文件 -->
<properties resource="jdbc.properties">
</properties>
resource=”jdbc.properties”——小配置文件存放路径
ii.${key}获取小配置文件中对应的值
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/
<property name="password" value="${password}"/>
</dataSource>
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
作用:
i.根据程序员书写的Mapper文件,自动创建mapper文件对应的java类(DAO接口的实现类)
ii.SqlSession内部封装了Connection对象
iii.SqlSession控制事务
SqlSession.commit——Connection.commit
SqlSession.rollback——Connection.rollback
注意:实战开发中,增删改需要控制事务 查询不需要控制事务
2-3 MyBatis 的开发步骤
i.建表
ii.写实体
iii.DAO接口
iiii.Mapper文件做DAO的实现
public User selectByID(Integer id);
<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”
v.Mapper文件的注册
<mappers>
<mapper resource = "com/hibiscidai/dao/UserMapper.xml" />
</mappers>
vi.MyBatis核心API测试
@Test
public void testMybatis() throws Exception {
// 读取mybatis-config配置文件
InputStream stream = Resources.getResourceAsStream("mybatis-config.xml");
// 创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream);
// 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建DAO的实现类
UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
// 调用DAO中相关方法
User user = userDAO.selectByID(1);
System.out.println(user);
}
3 参数绑定
3-1 Mybaits代码中形参名与mapper文件中的#{}的名字没有必然联系
public User selectByID(Integer id);
<select id="selectByID" parameterType="int" resultType="com.hibiscidai.entity.User">
select * from t_user where id=#{hibiscidai}
</select>
Integer id–hibiscidai
3-2 Mapper文件中可以通过下标的形式,代表接口中的形参
public User selectByID(Integer id);
<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 可以通过下标的形式进行操作
public User selectByNameAndPassword(String username, String password);
<select id="selectByNameAndPassword" resultTpe="com.baizhi.entity.User">
select * from t_user where username=#{0} and password=#{1}
</select>
3-3-2@Param注解进行参数绑定[建议]
注:
<![CDATA[]]>
mybaits中消除xml大小写
public User selectByNameAndPassword(@Param("u")String username, @Param("p") String password);
<select id="selectByNameAndPassword" resultType="com.hibiscidai.entuty.User">
select * from t_user where username=#{u} and password=#{p}
</select>
3-3-3 使用集合(map)进行传参[早期]
Map<String, String> map = new HashMap<String, String>();
map.put("username", "hibiscidai");
map.put("passowrd", "123456");
User user = userDAO.selectByNameAndPassword(map);
select * from t_user where username=#{username} and password=#{passowrd}
public User selectByNameAndPassword(Map<String, String> params);
4 MyBatis中CUD(增删改)
注意:在MyBatis应用的过程中,处理CUD时,必须要手工控制事务,否则操作不执行
sqlSession.commit();
sqlSession.rollback();
4-1 删除
public void delete(Integer id);
<delete id="delete">
delete from t_user where id=#{id}
</delete>
4-2 修改
public void update(User user);
User {
id
username
password
}
<update id="update">
update t_user set username=#{username}, password=#{password} where id=#{id}
</update>
4-3 插入
Sequence序列进行主键插入[Oracle]
public void insert(User user);
User {
id = null
username = hibiscidai
passowrd = 123456
}
<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层
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类
特点:清零及资源 不能被多线程共享
1.创建DAO接口的实现类(动态代理设计思想 动态字节码技术)
2.SqlSession内部封装Connnection 一个SqlSession对应一个Connection
3.事务控制
SqlSession.commit
SqlSession.rollback
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 {
// 读取mybatis-config配置文件
stream = Resources.getResourceAsStream("mybatis-config.xml");
// 创建SqlSessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream);
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
throw new RuntimeException("读取配置文件失败");
} finally { // 关闭流
try {
stream.close();
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
}
/* 获取SqlSession对象 */
public static SqlSession opSqlSession() {
SqlSession sqlSession = tl.get();
// 非空判断
if (null == sqlSession) {
sqlSession = sqlSessionFactory.openSession();
tl.set(sqlSession);
}
return sqlSession;
}
/* 关闭SqlSession对象 */
public static void closeSqlSession() {
// 获取SqlSession
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();
}
/* 获取DAO实现 */
public static Object getMapper(Class clazz) {
SqlSession sqlSession = opSqlSession();
return sqlSession.getMapper(clazz);
}
}
6 ResultMap(结果映射,结果对应关系)
作用:解决了实体类与数据库中的表不匹配
6-1 定义ResultMap
<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
<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>
注意:如果在开发中,只解决列名不一致的问题,有简化的方式,起别名
<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处理
关系属性:把关系另一方作为本方属性进行存储
关系的方向性:
单向关系:只能从关系其中一方 找到关系的另一方
双向关系:从关系的双方都可以找到关系的另一方
级联查询:
PersonDAO.query(id) —> Person(passport)
PassportDAO.query(id) —> Passport(person)
看似是单表处理 实际完成多张表的操作
7-2-2 表
表中如何简历关联关系:外键
建外键规则:
一对一 随便建
一对多 建在多的一方
多对多 建在第三张表中
表中关系的方向行:天生的双向关系
注意
1.父没有外键 先插入
2.子表没有外键 先删除
7-2-3 DAO接口
有几个DAO, 对应写几个DAO
7-2-4 Mapper文件处理
自定义结果映射
8 关联关系的实战开发
8-1 1:1关联关系
<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)关系
Employee
id
username
age
salary
department
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)关系
Student
id
studentnumber
studentname
age
List<Course>
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
一个对象
<association property="" javaType="">
多个对象
<collection property="" oftype="">
9 动态SQL
作用:简化mapper文件的配置
9-1 Sql片段
<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
//根据教师的ID查询该教师
public Teacher selectByID(Integer id);
//根据教师的姓名查询该教师
public Teacher selectByName(String name);
//根据教师的序列号查询
public Teacher selectByNumber(String number);
//根据教师的id及姓名查询
public Teacher selectByIDAndName(@Param("id")Integer ID,@Param("name")String name);
使用where后
public Teacher selectByWhere(Integer id, String name, String number)
Mapper文件重构
未使用where
<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后
<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逻辑映射:
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}
<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号
新的写法:
<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
<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>
新的写法
<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 批量操作(批量删除,批量查询)
<select id="selectByIDs" resyltType="Teacher">
select * from t_teacher where id in
<foreach collection="array" open="(" items="ids" separator="," close=")">
#{ids}
</froeach>
</select>
select * from t_teacher where id in
<foreach collection="list" open="(" item="ids" separator=","close=")">
</foreach>
如果参数是list集合 collection属性值设置为list
10 MyBatis的缓存(Cache)
10-1 缓存简述
作用:
在应用程序与数据库之间建立内存缓冲,存储用户曾经查询过的数据
好处:
1.减少与数据库之间的频繁通信
2.内存中随机读写效率高于硬盘
问题:
1.内存造价高,内存物理上线不大 无法缓存海量数据
2.数据安全性差
原则:
缓存中存储的数据一定是经常需要查询的数据,而且不是经常需要修改的数据
10-2 缓存开启步骤
10-2-1 开启MyBatis的全局缓存
Mybatis-config.xml配置
<!-- 激活全局缓存 -->
<settings>
<setting name="cacheEnabled" value="true" />
</setting>
10-2-2 设置需要存储在缓存中的数据
<!-- cache标签的作用:本mapper文件中的所有有关查询的操作都会放入mybatis的缓存中 -->
<cache>
</cache>
<select id="selectByID" resultType="Person">
select * from t_person where id=#{id}
</select>
注意实体类起别名
10-2-3 放置在缓存中的实体对象都需要实现serializable接口
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