一、MyBaits
1. MyBatis简介(了解)
1.1. 什么是MyBatis
MyBatis 本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、 preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
总之,Mybatis对JDBC访问数据库的过程进行了封装,简化了JDBC代码,解决JDBC将结果集封装为Java对象的麻烦。
下图是MyBatis架构图:

(1)mybatis-config.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂
(2)基于SqlSessionFactory可以生成SqlSession对象
(3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。
(4)Executor是SqlSession底层的对象,用于执行SQL语句
(5)MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)
1.2. 为什么要使用MyBatis
思考:在开始之前,思考下如何通过JDBC查询Emp表中的所有记录,并封装到 一个List集合中返回。(演示:准备数据、导包、导入JDBC程序)
1、使用传统方式JDBC访问数据库:
(1)使用JDBC访问数据库有大量重复代码(比如注册驱动、获取连接、获取传输器、释放资源等);
(2)JDBC自身没有连接池,会频繁的创建连接和关闭连接,效率低;
(3)SQL是写死在程序中,一旦修改SQL,需要对类重新编译;
(4)对查询SQL执行后返回的ResultSet对象,需要手动处理,有时会特别麻烦;
2、使用mybatis框架访问数据库:
(1)Mybatis对JDBC对了封装,可以简化JDBC代码;
(2)Mybatis自身支持连接池(也可以配置其他的连接池),因此可以提高程序的效率;
(3)Mybatis是将SQL配置在mapper文件中,修改SQL只是修改配置文件,类不需要重新编译。
(4)对查询SQL执行后返回的ResultSet对象,Mybatis会帮我们处理,转换成Java对象。
…
总之,JDBC中所有的问题(代码繁琐、有太多重复代码、需要操作太多对象、释放资源、对结果的处理太麻烦等),在Mybatis框架中几乎都得到了解决!!
2. MyBatis快速入门
2.1. 准备数据
-- 1、创建数据库 yonghedb 数据库
create database if not exists yonghedb charset utf8; use yonghedb; -- 选择yonghedb数据库
-- 2、删除emp表(如果存在)
drop table if exists emp;
-- 3、在 yonghedb 库中创建 emp 表
create table emp( id int primary key auto_increment, name varchar(50), job varchar(50), salary double );
-- 4、往 emp 表中, 插入若干条记录
...
2.2. 创建工程,准备开发环境
创建工程,导入所需jar包、创建测试类
1、创建Maven的java工程
2、导入junit、mysql、mybaits、log4j等开发包
<dependencies>
<!-- junit单元测试 -->
<dependency>
<groupId>junit</groupId> <artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <version>5.1.32</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.8</version>
</dependency>
<!-- 整合log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId> <version>1.6.4</version>
</dependency>
</dependencies>
3、创建com.tedu.mybatis.TestMybatis01测试类,并提供findAll方法(查询emp表中所有的员工信息),开发步骤如下:
/** 练习1(快速入门): 查询emp表中的所有员工, 返回一个List<Emp>集合 * @throws IOException */
@Test
public void findAll() throws IOException {
//1.读取mybatis的核心配置文件(mybatis-config.xml)
//2.通过配置信息获取一个SqlSessionFactory工厂对象
//3.通过工厂获取一个SqlSession对象 //4.通过namespace+id找到要执行的sql语句并执行sql语句
//5.输出结果 }
2.3. 添加mybatis-config.xml文件
1、在src/main/resources目录下,创建mybatis-config.xml文件(MyBatis的核心配置文件)

2、mybatis-config.xml文件配置如下:
mybatis-config文件头信息如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- MyBatis的全局配置文件 -->
<configuration >
</configuration>
mybatis-config文件详细配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- MyBatis的全局配置文件 -->
<configuration >
<!-- 1.配置环境,可配置多个环境(比如:develop开发、test测试) -->
<environments default="develop">
<environment id="develop">
<!-- 1.1.配置事务管理方式:JDBC/MANAGED JDBC:将事务交给JDBC管理(推荐) MANAGED:自己管理事务
-->
<transactionManager type="JDBC"></transactionManager> <!-- 1.2.配置数据源,即连接池 JNDI/POOLED/UNPOOLED JNDI:已过时 POOLED:使用连接池(推荐) UNPOOLED:不使用连接池
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/> </dataSource>
</environment>
</environments>
<!-- 2.导入Mapper配置文件,如果mapper文件有多个,可以通过多个mapper标 签导入 -->
<mappers>
<mapper resource="EmpMapper.xml"/>
</mappers>
</configuration>
2.4. 添加EmpMapper.xml文件
1、在src/main/resources目录下,创建EmpMapper.xml文件 (实体类的映射文件)

2、EmpMapper.xml文件配置如下:
EmpMapper文件头信息如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--不同Mapper文件的namespace值应该保证唯一 在程序中通过[ namespace + id ]定位到要执行哪一条SQL语句
-->
<mapper namespace="">
</mapper>
EmpMapper文件详细配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--不同Mapper文件的namespace值应该保证唯一 在程序中通过[ namespace + id ]定位到要执行哪一条SQL语句
-->
<mapper namespace="EmpMapper">
<!-- 通过select、insert、update、delete标签声明要执行的SQL -->
<!-- 练习1: 查询emp表中的所有员工信息 resultType指定查询的结果将会封装到什么类型中 即使最终返回的结果是集合(List<Emp>),resultType也只需要指定集合中的泛 型即可!
-->
<select id="findAll" resultType="com.tedu.pojo.Emp"> select * from emp
</select>
</mapper>
2.5. 添加并编写Emp实体类
注意:在当前实例中,Emp类中的属性和数据库表的字段名称必须一致,否则将会无法将结果集封装到Java对象中。
在src/main/java目录下创建 com.xxx.pojo.Emp类,并编辑Emp类:提供私有属性以及对应的getter方法、setter方法,并重写toString方法
package com.tedu.pojo;
/*** 实体类,用于封装Emp表中的一条用户信息 */
public class Emp {
//1.声明实体类中的属性
private Integer id;
private String name;
private String job;
private Double salary;
//2.提供对应的getter和setter方法
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
//3.重写toString方法
@Override
public String toString() {
return "Emp [id=" + id + ", name=" + name + ", job=" + job + ", salary=" + salary + "]";
}
}
2.6. 实现测试类,并测试
1、实现findAll方法,代码如下:
/** 练习1(快速入门): 查询emp表中的所有员工, 返回一个List<Emp>集合 * @throws IOException */
@Test
public void findAll() throws IOException {
//1.读取mybatis的核心配置文件(mybatis-config.xml)
InputStream in = Resources .getResourceAsStream("mybatis-config.xml");
//2.通过配置信息获取一个SqlSessionFactory工厂对象
SqlSessionFactory fac = new SqlSessionFactoryBuilder().build( in );
//3.通过工厂获取一个SqlSession对象
SqlSession session = fac.openSession();
//4.通过namespace+id找到要执行的sql语句并执行sql语句
List<Emp> list = session .selectList("EmpMapper.findAll");
//提交事务
session.commit();
//5.输出结果
for(Emp e : list) {
System.out.println( e );
}
}
2、执行findAll方法,输出结果
2.7. 加入log4j日志框架
# Global logging configuration log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
mybatis默认使用log4j作为输出日志信息。
只要将该文件放在指定的位置,log4j工具会自动到指定位置加载上述文件,读取文件中的配置信息并使用!
3. MyBatis入门细节
3.1. mybatis-config.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- MyBatis的全局配置文件 -->
<configuration >
</configuration>
mybatis-config文件详细配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- MyBatis的全局配置文件 -->
<configuration >
<!-- 1.配置环境,可配置多个环境(比如:develop开发、test测试) -->
<environments default="develop">
<environment id="develop">
<!-- 1.1.配置事务管理方式:JDBC/MANAGED JDBC:将事务交给JDBC管理(推荐) MANAGED:自己管理事务
-->
<transactionManager type="JDBC"></transactionManager> <!-- 1.2.配置数据源,即连接池 JNDI/POOLED/UNPOOLED JNDI:已过时 POOLED:使用连接池(推荐) UNPOOLED:不使用连接池
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/> </dataSource>
</environment>
</environments>
<!-- 2.导入Mapper配置文件,如果mapper文件有多个,可以通过多个mapper标 签导入 -->
<mappers>
<mapper resource="EmpMapper.xml"/>
</mappers>
</configuration>
environments 标签:该标签内部可以配置多个environment,即多种环境,每种环境可以做不同配置或连接不同数据库。例如,开发、测试、生产环境可能需要不同的配置,连接的数据库可能也不相同,因此我们可以配置三个environment,分别对应上面三种不同的环境。
但是要记住,environment可以配置多个,但是最终要使用的只能是其中一个!
environment 标签:内部可以配置多种配置信息,下面介绍事务管理配置和数据源配置。
transactionManage 标签:事务管理配置,mybatis中有两种事务管理方式,也就是
type="[JDBC|MANAGED]。
**JDBC:这个配置就是直接使用了 JDBC的提交和回滚设置,它依赖于从数据源得到的连 接来管理事务范围。推荐使用。 **
MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。需要自己手动添加并 管理。不推荐使用
JNDI:已过时,不推荐使用!
POOLED:使用连接池,mybatis会创建连接池,并从连接池中获取连接访问数据库,在 操作完成后,将会把连接返回连池。
UNPOOLED:不使用连接池,该方式适用于只有小规模数量并发用户的简单应用程序上。
mappers 标签:用于导入mapper文件的位置,其中可以配置多个mapper,即可以导入多个mapper文件。
3.2. EmpMapper.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--不同Mapper文件的namespace值应该保证唯一 在程序中通过[ namespace + id ]定位到要执行哪一条SQL语句
-->
<mapper namespace="EmpMapper">
<!-- 通过select、insert、update、delete标签声明要执行的SQL -->
<!-- 练习1: 查询emp表中的所有员工信息 resultType指定查询的结果将会封装到什么类型中 即使最终返回的结果是集合(List<Emp>),resultType也只需要指定集合中的泛 型即可!
-->
<select id="findAll" resultType="com.tedu.pojo.Emp"> select * from emp
</select>
</mapper>
(1)第1行是xml的文档声明,用于声明xml的版本和编码
(2)第2、3、4行,引入了xml约束文档,当前xml文档将会按照mybatis-3- mapper.dtd文件所要求的规则进行书写。
(3)Mapper标签:根标签,其中namespace(名称空间,也叫命名空间),要求不能重复。在程序中通过【namespace + id 】定位到要执行哪一条SQL语句
(4)select标签:用于指定将来要执行的各种SQL语句。标签上可以声明属性,下面介绍常用的属性:id、resultType、resultMap
id属性:要求值不能重复。将来在执行SQL时,可以通过【namespace + id】找到指定SQL并执行。
resultType属性:从这条SQL语句中返回所期望类型的类的完全限定名称(包名+类名)。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。
简而言之,resultType控制查询SQL执行后返回值的类型或集合中的泛型,例如查询emp表中的单条记录,返回值是一个Emp对象,因此,
resultType=“com.xxx.pojo.Emp”;
如果查询emp表中的多条记录,返回值是一个List,此时resultType的值应该集合中的泛型,因此resultType=“com.xxx.pojo.Emp”;
resultMap属性:复杂对象结构(例如多表关联查询等)。 使用 resultType 或 resultMap,但不能同时使用。
4. MyBatis增删改查
1、编辑EmpMapper.xml文件
<!-- 练习02: 新增员工信息: 赵云 保安 6000 -->
<insert id="testInsert02" >
insert into emp value( null, '赵云', '保安', 6000 )
</insert>
<!-- 练习03: 修改员工信息:赵云 保镖 20000 -->
<update id="testUpdate03">
update emp set job='保镖', salary=20000 where name='赵云'
</update>
<!-- 练习04: 删除name为'赵云'的记录 -->
<delete id="testDelete04">
delete from emp where name='赵云'
</delete>
2、编写TestMybatis类
//1.读取mybatis的核心配置文件(mybatis-config.xml)
InputStream in = Resources.getResourceAsStream( "mybatis-config.xml" );
//2.根据配置信息获取SqlSession工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build( in );
//3.通过SqlSession工厂获取一个SqlSession对象(打开与数据库的连接)
SqlSession session = factory.openSession( true ); //true表示自动提交事务
//4.1.新增员工信息: 赵云 保安 6000
//int rows = session.insert( "EmpMapper.testInsert02" );
//4.2.修改员工信息:赵云 保镖 20000
//int rows = session.update( "EmpMapper.testUpdate03" );
//4.3.删除name为'赵云'的记录
int rows = session.delete( "EmpMapper.testDelete04" );
//session.commit(); //提交事务
5. mybatis中的占位符
5.1. #{}占位符
在上面的增删改查操作中,SQL语句中的值是写死在SQL语句中的,而在实际开发中,此处的值往往是用户提交过来的值,因此这里我们需要将SQL中写死的值替换为占位符。
在mybatis中占位符有两个,分别是 #{} 占位符 和 KaTeX parse error: Expected 'EOF', got '#' at position 12: {} 占位符: **#̲{}: 相当于JDBC中的问号…{} :是为SQL片段(字符串)进行占位,将传过来的SQL片段直接拼接在${} 占位符所在的位置,不会进行任何的转义处理。(由于是直接将参数拼接在SQL语句中,因此可能会引发SQL注入攻击问题)
需要注意的是:使用 ${} 占位符为SQL语句中的片段占位时,即使只有一个占位符,需要传的也只有一个参数,也需要将参数先封装再传递!**
练习:
在mapper文件中编写SQL语句:
<!-- 练习05: 查询emp表中指定id的员工信息 -->
<select id="findById05" resultType="com.tedu.pojo.Emp">
select * from emp where id=#{
id}
</select>
<!--练习06:新增员工信息:张飞Java工程师 15000 -->
<insert id="insert06">
insert into emp value(null,#{
name},#{
job},#{
salary})
</insert>
<!-- 练习07:修改员工信息:张飞架构师 25000 -->
<update id="update07">
update emp set job=#{
job},salary=#{
salary}
where name=#{
name}
</update>
<!--练习08:根据条件查询emp表中的员工信息 -->
<select id="findAll08" resultType="com.xxx.pojo.Emp">
select * from emp ${
sqlStr}
</select>
<delete id="delete09">
delete from emp where id=#{
id} <!--如果id=${
id} 会出现注入攻击,删除全部 -->
</delete>
Java代码实现:
SqlSession session;
@Before
public void init() throws IOException {
//1.读取mybatis的核心配置文件(mybatis-config.xml)
InputStream in = Resources.getResourceAsStream( "mybatis-config.xml" );
//2.根据配置信息获取SqlSession工厂对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build( in );
//3.通过SqlSession工厂获取一个SqlSession对象(打开与数据库的连接)
session = factory.openSession( true ); //true
}
//=============== mybatis中的占位符 ===============
/** 练习05: 查询emp表中指定id的员工信息 */
@Test
public void testFindById05() {
Integer id = 8;
Emp emp = session.selectOne( "EmpMapper.findById05", id );
System.out.println( emp );
}
/* 练习06:新增员工信息:张飞Java工程师 15000
* 如果SQL语句有多个占位符,就需要传递多个参数,多参数如何传递
* 1》通过map集合进行封装(通用)
* 2》通过PoJo对象进行封装
* */
@Test
public void testInsert06() {
/*
* //声明一个Map集合,将SQL参数封装到Map集合中
* Map<String,Object> map = new HashMap<>();
* map.put("name","张飞");
* map.put("job","Java开发工程师");
* map.put("salary",15000);
* session.insert("EmpMapper.insert06",map);
*/
//声明一个Emp对象,将参数封装到Emp对象中
Emp emp =new Emp();
emp.setName("关羽");
emp.setJob("士兵");
emp.setSalary(20000d);
session.insert("EmpMapper.insert06",emp);
}
/* 练习07:修改员工信息:张飞架构师 25000 */
@Test
public void testUpdate07() {
//声明一个map集合,将SQL参数封装到map集合中
Map<String,Object> map=new HashMap<>();
map.put("name","张飞");
map.put("job","架构师");
map.put("salary",25000d);
session.update("EmpMapper.update07",map);
}
/*练习08:根据条件查询emp表中的员工信息*/
@Test
public void testFindAll08() {
Map<String,Object> map=new HashMap<String,Object>();
// map.put("sqlStr","where salary>3500");
map.put("sqlStr","where name like '刘%'");
List<Emp> list = session.selectList("EmpMapper.findAll08",map);
for(Emp emp:list) {
System.out.println(emp);
}
}
@Test
public void testDelete09() {
Map map=new HashMap();
map.put("id","1 or 1=1");
session.delete("EmpMapper.delete09",map);
}
在上面的增删改查练习中,当SQL语句中包含的参数值是传递过来的,在SQL语句中我们会通过 #{} 占位符进行占位,在SQL语句真正执行时,再将传递过来的值替换SQL语句中的占位符。
其实, #{} 就是JDBC中的问号(?)占位符,因此为了安全考虑,在执行时会对传递过来的字符串和日期类型高的值进行转译处理。
例如:查询指定name的员工信息,SQL语句为:
select * from emp where name=#{name}
其实就等价于JDBC中: select * from emp where name=? ,
如果传过来的参数值为:张三,那么最终执行的SQL语句为:
– 在参数替换占位符的同时进行了转义处理(在值的两边加上了单引号)
select * from emp where name=‘张三’
5.2. ${}占位符
那么如果我们在传递的时候不是一个参数值,而是一个SQL片段呢?
例如:在查询时,我们想动态的传递查询的列:select #{columns} from emp
此时传递过来的应该是一个SQL片段,不同于上面的参数值,如果此时还用 # {} ,也会像上面一样被转译处理: select ‘id,name,job’ from emp ,这不是我们希望看到的!
如果不想让传过来的SQL片段被转译处理,而是直接拼接在SQL语句中,那么这里可以使用 ${} ,例如:
select ${columns} from emp
拼接之后: select id,name,job from emp
练习:
在mapper文件中编写SQL语句:
<!-- 练习9: 动态指定要显示的列 -->
<select id="findAll2" resultType="com.tedu.pojo.Emp">
select ${
cols

最低0.47元/天 解锁文章
534

被折叠的 条评论
为什么被折叠?



