回顾
1. preparedStatement
解决sql注入问题
使用步骤
1.获取连接
2.编写sql【?代替实际参数】
3.获取sql预编译执行对象
4.设置实际参数
5.执行sql语句并返回结果
6.处理结果
7.释放资源
2. 连接池
减轻服务器压力,提高连接复用性
sun公司提供了DataSource连接池规范
Connection getConnection();
Druid
连接池工具类
3. 案例:用户登录
三层架构+面向接口编程
dao层使用的原生JDBC
1.代码繁琐
2.sql语句与java代码有耦合
3.封装结果集繁琐
Mybatis入门
今日目标
1. 框架介绍
2. mybatis介绍
3. mybatis快速入门【重点】
4. 映射文件概述
5. mybatis原生的增删改查【了解】
6. 抽取工具类【spring可以代替】
7. 核心配置文件
8. 核心api概述
9. mybatis实现dao层
传统dao(接口+实现类)
接口dao(接口)【重点】
10. 基于接口增删改查
一 框架简介
为什么学习框架?
面试必问、开发比用技术,简化代码,提高效率
二 Mybatis简介
2.1 ORM概述
ORM(object Relational Mapping)对象关系映射
常用ORM框架有:hibernate(全自动ORM映射)、mybatis(半自动ORM映射)、jpa
2.2 Mybatis介绍
历史
- MyBatis本是apache的一个开源项目,名为iBatis。
- 2010年这个项目由apache迁移到了google,并且改名为MyBatis。
- 2013年迁移到Github。
简介
MyBatis官网地址:http://www.mybatis.org/mybatis-3/
- mybatis是一款优秀的持久层框架,他不需要项JDBC繁琐编写代码,只需要开发人员关注(接口+sql)
- 它采用了简单的xml配置+接口方式实现增删改查,开发时我们只需要关注SQL本身
三 Mybatis快速入门【重点】
需求
查询数据库user表的所有记录,封装到User对象中。
3.1 步骤分析
- ① 创建mybatis_db数据库和user表
- ② 创建java项目,导入jar包
(mysql驱动、mybatis、log4j日志) - ③ 创建User实体类
- ④ 编写映射文件UserMapper.xml
- ⑤ 编写核心文件SqlMapConfig.xml
- ⑥ 编写测试代码
3.2 代码实现
① 创建mybatis_db数据库和user表
从今天的资料中,执行sql脚本,创建库,创建表
② 创建java项目,导入jar包
③ 创建User实体类
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 省略 getter、setter
}
④ 编写映射文件UserMapper.xml
⑤ 编写核心文件SqlMapConfig.xml
⑥ 编写测试代码
// 查询所有
@Test
public void testFindAll() throws Exception {
// 1.加载核心配置文件(SqlMapConfig.xml)
// 2.构建SqlSessionFactory工厂对象
// 3.通过工厂创建SqlSession会话对象(Connection)
// 4.执行sql语句
// 5.释放资源
}
public class UserMapperTest {
// 查询所有
@Test
public void testFindAll() throws Exception {
// 1.加载核心配置文件(SqlMapConfig.xml)
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.构建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3.通过工厂创建SqlSession会话对象(Connection)
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4.执行sql语句 (命名空间+id)
List list = sqlSession.selectList("UserMapper.findAll");
for (User user : list) {
System.out.println(user);
}
// 5.释放资源
sqlSession.close();
}
}
四 Mybatis映射文件概述
五 Mybatis增删改查【作业】
5.1 新增
① 编写映射文件UserMapper.xml
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
② 编写测试代码
// 新增
@Test
public void testSave()throws Exception{
// 1.加载核心配置文件(SqlMapConfig.xml)
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.构建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3.通过工厂创建SqlSession会话对象(Connection)
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4.执行sql语句
User user = new User();
user.setUsername("jack");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("北京");
int i = sqlSession.insert("UserMapper.save", user);
if (i>0) {
System.out.println("添加成功");
}
// 注意:mybatis需要手动提交事务(DML)
sqlSession.commit();
// 5.释放资源
sqlSession.close();
}
③ 知识小结
- 插入语句insert标签
- 在映射文件中使用parameterType属性指定插入数据类型
- sql语句#{实体属性名} 表示?占位符
- 我们插入操作API是 sqlSession.insert("命名空间.id", 实体对象);
- DML类型语句mybatis需要手动提交事务 sqlSession.commit();
5.2 修改
① 编写映射文件UserMapper.xml
update user set username = #{username},birthday = #{birthday},sex = #{sex},
address = #{address} where id = #{id}
② 编写测试代码
// 修改
@Test
public void testUpdate()throws Exception{
// 1.加载核心配置文件(SqlMapConfig.xml)
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.构建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3.通过工厂创建SqlSession会话对象(Connection)
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4.执行sql语句
User user = new User();
user.setId(50);
user.setUsername("lucy");
user.setBirthday(new Date());
user.setSex("女");
user.setAddress("上海");
sqlSession.update("UserMapper.update", user);
// DML语句,手动提交事务
sqlSession.commit();
// 5.释放资源
sqlSession.close();
}
③ 知识小结
- 修改操作使用update标签
- 修改操作的API使用的 sqlSession.update("命名空间.id", 实体对象);
5.3 删除
① 编写映射文件UserMapper.xml
delete from user where id = #{id}
② 编写测试代码
// 删除
@Test
public void testDelete() throws Exception {
// 1.加载核心配置文件(SqlMapConfig.xml)
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.构建SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3.通过工厂创建SqlSession会话对象(Connection)
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4.执行sql语句
sqlSession.delete("UserMapper.delete", 50);
// 提交事务
sqlSession.commit();
// 5.释放资源
sqlSession.close();
}
③ 知识小结
- 删除语句使用delete标签
- 如果parameterType是引用数据类型 #{实体属性名}
- 如果parameterType是简单数据类型 #{键名知意}
- 删除操作API sqlSession.delete("命名空间.id", Object);
5.4 知识小结
* 查询所有
代码:
List list = sqlSession.selectList("UserMapper.findAll");
映射文件:
* 新增
代码:
sqlSession.insert("UserMapper.save", user);
映射文件:
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
* 修改
代码:
sqlSession.update("UserMapper.update", user);
映射文件:
update user set username = #{username},birthday = #{birthday},
sex = #{sex},address = #{address} where id = #{id}
* 删除
代码:
sqlSession.delete("UserMapper.delete", 50);
映射文件:
delete from user where id = #{id}
六 抽取工具类【抄一遍】
将mybatis测试代码的通用部分进行抽取,简化书写提高效率
// 课下抄一遍....
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
// 在静态代码块中(1.加载核心配置文件 2.构建工厂对象)
static {
try {
// 1.加载核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.构建工厂对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
// 提供获取sqlSession的静态方法
public static SqlSession openSession() {
return sqlSessionFactory.openSession();
}
// 提供提交事务和释放资源方法
public static void close(SqlSession sqlSession){
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
}
}
需求
根据指定id,查询User对象
编写映射文件UserMapper.xml
编写测试代码
// 查询一个
@Test
public void testFindById() throws Exception {
// 1.获取sqlSession(根据工具类)
SqlSession sqlSession = MyBatisUtils.openSession();
// 2.执行sql
User user = sqlSession.selectOne("UserMapper.findById", 41);
System.out.println(user);
// 3.关闭sqlSession
MyBatisUtils.close(sqlSession);
}
七 Mybatis核心文件概述
7.1 核心配置文件层级关系
7.2 常用配置标签解析
① environments标签
- 数据库环境的配置,支持多环境配置
1. 其中,事务管理器(transactionManager)类型有两种:
* JDBC:
这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
* MANAGED:
这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。
例如:mybatis与spring整合后,事务交给spring容器管理。
2. 其中,数据源(dataSource)常用类型有二种:
* UNPOOLED:
这个数据源的实现只是每次被请求时打开和关闭连接。
* POOLED:
这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
② properties标签
- 加载外置的properties配置文件
③ typeAliases标签
- 为 Java 类型设置一个短的名字(类型别名)
mybatis框架内置了一些java类型的别名
④ mappers标签
- 用于加载映射文件,加载方式有如下几种:
1. 加载指定的src目录下的映射文件,例如:【快速入门】
2. 加载指定接口的全限定名,例如:【注解开发时使用....】
3. 加载并扫描指定包下所有的接口,例如:【基于接口扫描方式加载】
mybatis文件的关系介绍
7.3 核心配置文件标签顺序
7.4 知识小结
properties标签:该标签可以加载外部的properties文件
typeAliases标签:设置类型别名
environments标签:数据源环境配置
mappers标签:加载映射配置
八 Mybatis的API概述
8.1 API介绍
① Resources
- 加载mybatis的核心配置文件
// 加载mybatis的核心配置文件,获取io流
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
② SqlSessionFactoryBuilder
- 根据mybatis的核心配置文件构建出SqlSessionFactory工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
③ SqlSessionFactory
- 用于创建SqlSession会话对象(相当于Connection对象)
- 这是一个工厂对象,对于这种创建和销毁都非常耗费资源,一个项目中只需要存在一个即可
// DML类型语句,需要手动提交事务
SqlSession openSession();
// 设置是否开启自动提交事务的会话对象,如果设置true,自动提交【了解】
SqlSession openSession(boolean autoCommit);
④ SqlSession
- 这是Mybatis的一个核心对象。我们基于这个对象可以实现对数据的CRUD操作
- 对于这个对象应做到每个线程独有,每次用时打开,用完关闭
执行语句的方法主要有
T selectOne(String statement, Object parameter);
List selectList(String statement, Object parameter);
int insert(String statement, Object parameter);
int update(String statement, Object parameter);
int delete(String statement, Object parameter);
操作事务的方法主要有
void commit();
void roolback();
8.2 工作原理【了解】
九 Mybatis实现Dao层
9.1 传统开发方式【了解】
① 将快速入门java工程复制一份
② 编写UserMapper接口
public interface UserMapper {
// 查询所有
public List findAll();
}
③ 编写UserMapper实现类
public class UserMapperImpl implements UserMapper {
@Override
public List findAll() {
try {
// 1.加载核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.构建工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3.创建会话
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4.执行sql
List list = sqlSession.selectList("UserMapper.findAll");
// 5.释放资源
sqlSession.close();
return list;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
④ 编写UserMapper.xml映射文件
⑤ 模拟service测试
public class UserMapperTest {
// 模拟service
@Test
public void test01() throws Exception {
// 调用dao层代码
UserMapper userMapper = new UserMapperImpl();
List list = userMapper.findAll();
System.out.println(list);
}
}
⑥ 知识小结
1. 编写UserMapper接口
2. 编写UserMapperImpl实现类
3. 编写UserMapper.xml映射
课下可以完善,新增、修改、删除、查询一个...
9.2 接口代理开发方式【重点】
采用 Mybatis 的基于接口代理方式实现 持久层 的开发,这种方式是我们后面进入企业的主流。
基于接口代理方式的开发只需要:编写接口和映射文件,Mybatis 框架会为我们动态生成实现类的对象。
接口开发规范
1. Mapper映射文件的namespace与Mapper接口全限定名一致
2. Mapper接口的方法名与id的属性名一致
3. 方法的参数类型与parameterType属性类型一致
4. 方法的返回值类型与resultType属性类型一致
5. 映射文件需要与接口在同一个包下,文件名和接口名相同:扫描包,加载所有的映射文件
① 将传统daojava工程复制一份
② 编写UserMapper接口
public interface UserMapper {
// 查询所有
public List findAll();
}
③ 编写UserMapper.xml映射文件
④ 模拟service测试
public class UserMapperTest {
// 模拟service测试
@Test
public void test01() throws Exception {
// 需要通过mybatis帮你根据接口规范创建实现类
SqlSession sqlSession = MyBatisUtils.openSession();
// 创建代理对象(实现类)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 执行sql
List list = userMapper.findAll();
System.out.println(list);
// 关闭会话
MyBatisUtils.close(sqlSession);
}
}
⑤ 基于接口代理方式的内部执行原理
使用了JDK动态代理技术,帮我们创建了接口的实现类,底层还是执行SqlSession.insert() | update()
十 接口代理的增删改查【大作业...】
10.1 UserMapper接口
public interface UserMapper {
// 查询所有
public List findAll();
// 新增
public void save(User user);
// 修改
public void update(User user);
// 删除
public void delete(Integer id);
// 查询一个
public User findById(Integer id);
}
10.2 UserMapper.xml 映射文件
insert into user (username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
update user set username = #{username},birthday = #{birthday},sex = #{sex},
address = #{address} where id = #{id}
delete from user where id = #{id}
10.3 测试代码
public class UserMapperTest {
// 模拟service测试
@Test
public void test01() throws Exception {
// 需要通过mybatis帮你根据接口规范创建实现类
SqlSession sqlSession = MyBatisUtils.openSession();
// 创建代理对象(实现类)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 执行sql
List list = userMapper.findAll();
System.out.println(list);
// 关闭会话
MyBatisUtils.close(sqlSession);
}
// 测试新增
@Test
public void testSave()throws Exception{
// 需要通过mybatis帮你根据接口规范创建实现类
SqlSession sqlSession = MyBatisUtils.openSession();
// 创建代理对象(实现类)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setUsername("德玛西亚");
user.setSex("男");
user.setAddress("约德尔城");
user.setBirthday(new Date());
userMapper.save(user);
// 关闭会话
MyBatisUtils.close(sqlSession);
}
// 测试修改
@Test
public void testUpdate()throws Exception{
// 需要通过mybatis帮你根据接口规范创建实现类
SqlSession sqlSession = MyBatisUtils.openSession();
// 创建代理对象(实现类)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setId(52);
user.setUsername("卡特琳娜");
user.setSex("女");
user.setAddress("天使之城");
user.setBirthday(new Date());
userMapper.update(user);
// 关闭会话
MyBatisUtils.close(sqlSession);
}
// 删除
// 查询一个 课下作业
}
老师下午总结
疑惑|拓展
接口代理方式实现mybatis
- 导入jar
-
编写SqlMapConfig核心配置文件和日志文件,文件必须要放入src的根目录下
-
编写接口 , 如果你还没有User实体类需要编写User实体类
package com.itheima.dao; import com.itheima.model.User; import java.util.List; public interface UserDao { public List
findAll(); public void save(User user); }
-
编写接口对应的Mapper文件(Mapper文件需要与Dao接口同名并且在同一个包中)
insert into user values(null,#{username},#{birthday},#{sex},#{address})
-
测试
package com.itheima.test; import com.itheima.dao.UserDao; import com.itheima.model.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class MybatisTest { @Test public void test01() throws IOException { //1. 加载SqlmapCOnfig配置文件 InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2. 构建SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3. 得到Sqlsession SqlSession sqlSession = sqlSessionFactory.openSession(); //4. 得到接口的代理对象 mybatis帮你实现了该接口的所有方法,并返回该接口的代理对象给你 UserDao userDao = sqlSession.getMapper(UserDao.class); //5. 执行方法 List
list = userDao.findAll(); System.out.println("查询的对象:"+ list); //6. 提交事务,关闭sqlSesion sqlSession.commit(); sqlSession.close(); } }
3mapper与SqlMapConfig文件的模板创建
mybatis常见的问题
- 使用mapper标签引入xml文件的时候使用了.没偶遇使用斜杆
-
例子:
-
- mapper文件的名称空间没有与接口对应, 必须要求是mapper文件的文件名与接口名一致,而且必须是全路径
日志包的作用
常见的标签
用于加载properties文件
今日重点
- 使用接口动态代理的方式实现CURD
学习反馈
反馈 | 回复 |
---|---|
今天的知识需要再消化消化 感觉难度有点大。。。 | 不难,记住建立模板那就可以了 |
今天内容稍微有些多,老师能不能再讲一下mybatis原理 | 已经实现 |
老师,我们在做增删改查时,可以把mybatis给我们做了哪些事情讲下 | 已经实现 |
接口代理这一块有点模糊 | 那现场再来重新实现一次 |
映射文件中的parameterType和resultType分不清,什么时候用什么. 核心配置文件几个标签不懂 | parameterType代表的是形参的类型, resultType代表的是方法的返回值类型 |
今天的内容有点多,到了下午的内容没听好 | 接口代理方式 |
ybatis的usermapper.xml中写的sql需要传两个参数怎么写?(比如如果要登录就需要username与password两个参数,是将其封装到user对象中,还是使用map?又或者有什么其他方法写?) mybatis参数对象/返回对象中有list或map(比如班级中有多个学生),可以自动识别吗? 配置文件的放置有强制规定吗? | 后期会讲解到取出list和map的参数 |
希望能再讲一下接口代理开发方式,不是特别清晰 | 刚刚已经讲过了. |
好难 |
答疑区
疑问 | 答复 |
---|---|
咱们不讲SSS吗,这个不流行吗? | SSS , 是spring 全家桶, 后面课程会有涉及。 |
哦哦,我的意思是spring提供的dao层的解决方案咱们不学吗? | spring data jpa , jdbcTemplate ,后面会有提到 |
框架师是什么意思?是熟练掌握框架,还是自己可以封装框架?高级工程师==框架师吗? | 软件架构师一般都是具备计算机科学或软件工程的知识,由程序员做起,然后再慢慢发展为架构师的。架构师关注的是软件组织新产品的开发与集成.是软件项目的总体设计师. |
请问导入mybatis包为什么不建议选择最新版本? | 所有的新东西除非调研过,没问题才可以试行、一段时间后再在核心业务系统使用。 企业里面以稳为主,而不是个人尝试最新技术为驱动。 |
日志的作用是啥呢 | 日志可以记录mybatis执行的过程,比如执行了哪些sql语句这些信息 |
ORM映射的时候表名和实体类的类名不一样也可以吧?只需要保证属性和字段一样就行吗 | 是的,表名与类名可以不一致,今天实体类的属性名与字段名要一致,后面也可以不一致。 |
Integer包装类中可以有null值是吗 | 包装类型都可以设置为null; |
为什么使用resulttype属性呀 | resulttype是查询结果封装成什么样的类型.我们现在是封装成User对象 |
dtd约束是什么 | dtd是属于xml的约束,主要是约束xml文件能出现哪些元素 |
mysql配置文件默认使用连接池吗? | 不要慌 都讲的 |
sqlSession中有select系列的方法 和 getMapper的方法 select方法好像不是过时了吗。 后面是用哪种方式,getMapper加接口的方式吗 | 是的 |
sqlSession.close()底层是调用的连接池close()吗 | 是的 |
请问:第五步sqlSession.close()是把connection还给mybaties默认的连接池吧,老师? | 是的 |
老师 要是resultType里写整型是写Integer还是写int | int |
既然实体关系映射了,这里的新增为什么还要指定实体的属性啊 | 如果对象的成员变量和表中的字段不一样,那就办法映射了. |
假如增删改需要返回一个布尔型,sqlsession有没有重载的方法? | 这个是没有的,下面会讲到代理模式的实现, 既可以返回整数也可以返回布尔值。 |
@张云飞老师 所以说dml返回值是Int是固定的,只有参数,不用指定返回值 | 是的,没错. |
假如使用三层架构,这里的测试代码是不是需要卸载dao层 | 是的. |
parameterType里的数据类型不需要和表中字段的数据类型对应吗? | 和调用方法传入的参数类型一致.这里指定的是java类型 |
删除操作怎么知道撒删除哪一个记录的 没见传删除id啊 | 传入id为50 |
为什么设置静态成员变量要等于null呢?等于null如果取不到值调用不就空指针了吗? | 引用数据类型, 成员变量默认值就是null。 如果不指定肯定会空指针的。 |
老师,请问框架都是以jar包的形式导入,然后配置好配置文件就可以用了吗?? | 现在先用jar包的方式; 后面学了maven更简洁。 |
这个是动态代理对象吗?动态代理功能不是拦截对真实对象方法的直接访问,增强真实对象方法的功能。我怎么没看出来他拦截访问了呢 | UserDao mapper = sqlSession.getMapper(UserDao.class); getMapper方法拿到了接口的字节码对象.底层可以动态代理来创建子类对象.返回给你的就是代理对象 |
影响行数不需要返回值类型吧?比如增删改 | 不需要.默认int |