MyBatis框架
第一章 认识框架
1.1 什么是框架 frame
框架就是一个架子,表演节目,舞台已经搭建好,表演什么节目,看自己的需求了。
框架是一个半成品,对于Java语言来说,框架就是封装了别人的代码。在框架的基础上我们在进一步开发,拿来主义。
解决的是技术整合问题。软件开发环境和规模都很大,不可能任何一个项目的代码都从零开始,此时就需要一个非常优秀的框架把基础技术整合完毕,我们在他的基础上进一步开发。提高性能,易扩展,易维护,最终提高整个团队的开发效率。
1.2 如何使用框架
企业级大型项目开发,避免大炮打蚊子。
Java的框架是具有一些共性
- 导入jar包
- 框架运行细节定义,也就是编写配置文件(xml)
- 调用框架中的api
1.3 原生JDBC案例的问题
public class UserDaoImpl implements UserDao {
private String driverClass = "com.mysql.jdbc.Driver";
private String url="jdbc:mysql://localhost:3306/test";
private String username="root";
private String password="root";
@Override
public List<User> queryUserList()throws Exception {
List<User> list = new ArrayList<User>();
Class.forName(driverClass);
Connection conn = DriverManager.getConnection(url,username,password);
String sql = "select * from user where id=? and name = ?";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setObject(1,1);
pst.setObject(2,"a");
ResultSet rs = pst.executeQuery();
User user = null;
while (rs.next()){
user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setSex(rs.getString("sex"));
user.setBirthday(rs.getDate("birthday"));
user.setAddress(rs.getString("address"));
list.add(user);
}
rs.close();
pst.close();
conn.close();
return list;
}
}
- 频繁连接,释放数据库资源,降低系统性能
- SQL语句硬编码,难以维护
- 参数和占位符对应问题
- 结果集解析复杂,列名硬编码
1.4 MyBatis框架介绍
- Mybatis原本是Apache软件基金会的一个开源项目叫做iBatis,2010年这个项目由Apache迁移到了google code管理才改名为Mybatis,2013年又迁移到了GitHub。
- Mybatis是一个优秀的持久层框架(Dao层框架),它是对JDBC的封装,使得开发者只需要关注Sql语句(业务)本身即可,无需开发者处理加载驱动、获取连接、创建Statement等繁琐的过程。
- Mybatis最大的特点是把Sql语句写在XML配置文件当中。而且Mybatis执行完Sql语句之后可以以对象形式返回(POJO/POJO集合等)。
- Mybatis是一个实现了ORM思想的持久层框架。
- ORM:Object/Relation Mapping 对象/关系映射。
- ORM思想:将数据库中的关系数据表映射为JAVA中的对象,把对数据表的操作转换为对对象的操作,实现面向对象编程。因此ORM的目的是使得开发人员以面向对象的思想来操作数据库。
比如:原来insert使用的是insert into…,如果使用实现了ORM思想的持久层框架,就可以在Java程序中直接调用api,比如insert(User),达到操作对象即操作数据库的效果。Hibernate框架是一个全自动的ORM持久层框架,只需要编写POJO,在xml中定义好Pojo属性和数据表字段的映射/对应关系,就可以在java中实现类似 insert(User)的操作。Sql语句都不用写。但是因为性能等问题,市场占有率越来越低
Mybatis框架是一个半自动的ORM持久层框架,也可以在Java中实现类似 insert(User)的操作最终操作数据库,但是需要我们自己写Sql语句。Mybatis是目前比较流行的Dao层框架。
第二章 MyBatista框架快速入门
1.1准备测试数据
CREATE DATABASE `mybatis-example`;
USE `mybatis-example`;
CREATE TABLE `t_emp`(
emp_id INT AUTO_INCREMENT,
emp_name VARCHAR(100),
emp_salary DOUBLE,
PRIMARY KEY(emp_id)
);
INSERT INTO `t_emp`(emp_name,emp_salary) VALUES("tom",200.33);
1.2 创建JavaSE项目
导入MyBatis框架坐标
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
添加框架配置文件 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">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--
配置一个xml文件,存储的SQL语句
resource 配置的是存储SQL语句的文件路径和文件名
-->
<mapper resource="empMapper.xml"/>
</mappers>
</configuration>
添加SQL语句配置文件 employeeMapper.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="com.atguigu.mybatis.dao.EmployeeMapper">
<select id="selectEmployee" resultType="com.atguigu.pojo.Employee">
<!-- select 标签体文本,就是SQL语句-->
select emp_id empId ,emp_name empName ,emp_salary empSalary from t_emp
</select>
</mapper>
1.3 MyBatis框架核心API介绍
- SqlSessionFactoryBuilder类
- 作用1:读取配置文件
- 作用2:创建SqlSessionFactory接口对象
- 方法:build(输入流) 返回SqlSessionFactory接口对象
- SqlSessionFactory接口
- 作用:创建SqlSession接口对象
- 方法:openSession() 返回SqlSession接口对象
- SqlSession接口
- 作用1: 执行SQL语句
- 作用2 :事务控制
1.4 MyBatis框架实现数据表查询
/**
* MyBatis框架快速入门
* 需求:查询数据表t_emp,所有数据
* 查询结果List集合
*
* 实现步骤:
* 1: 创建输入流,绑定配置文件mybatis-config.xml (主配置文件)
* 2: 创建对象, SqlSessionFactoryBuilder
* 3: SqlSessionFactoryBuilder对象的方法build(传递输入流),build方法读取配置文件
* build方法返回对象: SqlSessionFactory对象
* 4:SqlSessionFactory对象的方法 openSession() 打开会话对象(连接数据库)
* openSession()方法,返回SqlSession对象 (等同于Connection)
* 5: SqlSession对象的方法执行SQL语句,返回查询结果集
* 6: 释放资源
*/
@Test
public void queryEmpByList(){
//1: 创建输入流,绑定配置文件mybatis-config.xml (主配置文件)
InputStream in =
MainTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
//2: 创建对象, SqlSessionFactoryBuilder
//对象作用是一个工厂,读取配置文件,创建另一个对象SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//3: SqlSessionFactoryBuilder对象的方法build(传递输入流),build方法读取配置文件
//build方法返回对象: SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
//4:SqlSessionFactory对象的方法 openSession() 打开会话对象(连接数据库)
// * openSession()方法,返回SqlSession对象 (等同于Connection)
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5: SqlSession对象的方法执行SQL语句,返回查询结果集
//SqlSession对象的方法,执行SQL语句
/**
* selectList() 执行SQL语句
* 参数:String:配置文件中的SQL语句
* 配置文件的 namespace属性+ . + 查询语句的id属性, 确定唯一性SQL语句
* 返回值: List
*/
List<Employee> employeeList = sqlSession.selectList("employeeMapper.selectEmployee");
//对集合,安全性判断
if ( employeeList != null && employeeList.size() > 0 ){
for (Employee employee : employeeList){
System.out.println(employee);
}
}
//6: 释放资源
sqlSession.close();
}
1.5 添加MyBatis执行日志
导入日志依赖jar包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
日志配置文件
#log4j日志级别如下:
#A:off 最高等级,用于关闭所有日志记录。
#B:fatal 指出每个严重的错误事件将会导致应用程序的退出。
#C:error 指出虽然发生错误事件,但仍然不影响系统的继续运行。
#D:warn 表明会出现潜在的错误情形。
#E:info 一般和在粗粒度级别上,强调应用程序的运行全程。
#F:debug 一般用于细粒度级别上,对调试应用程序非常有帮助。
#G:all 最低等级,用于打开所有日志记录。
#但log4j只建议使用4个级别,优先级从高到低分别是:
#error>warn>info>debug
log4j.rootLogger =debug,systemOut,logFile
#输出到控制台
log4j.appender.systemOut = org.apache.log4j.ConsoleAppender
log4j.appender.systemOut.layout = org.apache.log4j.PatternLayout
log4j.appender.systemOut.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.systemOut.Target = System.out
#输出到文件
log4j.appender.logFile = org.apache.log4j.FileAppender
log4j.appender.logFile.layout = org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.logFile.File = E:/log/log4j.log
log4j.appender.logFile.Encoding = UTF-8
#将日志输记录到MySQL数据库
#log4j.appender.logDB = org.apache.log4j.jdbc.JDBCAppender
#log4j.appender.logDB.layout = org.apache.log4j.PatternLayout
#log4j.appender.logDB.Driver = com.mysql.jdbc.Driver
#log4j.appender.logDB.URL = jdbc:mysql://localhost:3306/log4j?characterEncoding=utf-8
#log4j.appender.logDB.User = root
#log4j.appender.logDB.Password = root
#log4j.appender.logDB.Sql = INSERT INTO t_log4j(project_name,create_date,level,category,file_name,thread_name,line,all_category,message)values('mybatis','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')
#若出现问题:Log4j: ERROR Failed to load driver, java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
#解决方法:将log4j.properties 中每行后面的空格都删除就解决了.
1.6 MyBatis框架主配置文件详解
<?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">
<configuration>
<!--
environments 运行环境,多个
default="development" 默认环境 default 选择器作用
-->
<environments default="development">
<!--
environment 一个运行环境
id="development" id 唯一性
-->
<environment id="development">
<!--
transactionManager : 配置事务管理器
什么时候需要事务:新增,删除,修改,同时执行多个
type="JDBC" : 使用的事务管理器,是默认是的原始JDBC的事务管理器
type="MANAGERMENT" 事务管理交给第三方框架
-->
<transactionManager type="JDBC"/>
<!--
dataSource : 配置数据库的连接池
type="POOLED" ,使用MyBatis自带的连接池
type="UNPOOLED" ,不使用MyBatis自带的连接池,连接池使用德鲁伊+Spring
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
<!-- 配置运行环境,测试环境-->
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-example2"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
<!-- 配置运行环境,真实环境-->
<environment id="runtime">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-example3"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--
mappers 配置多个SQL语句的映射文件
-->
<mappers>
<!--
配置一个xml文件,存储的SQL语句
resource 配置的是存储SQL语句的文件路径和文件名
-->
<mapper resource="empMapper.xml"/>
</mappers>
</configuration>
第三章 MyBatis框架实现数据CRUD
1.1 根据ID查询用户
<select id="selectEmployeeById" parameterType = "int" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id ,emp_name ,emp_salary from t_emp where emp_id = #{id}
</select>
public void queryUserById() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
Employee emp = sqlSession.selectOne("com.atguigu.mybatis.dao.EmployeeMapper.selectEmployeeById",2);
System.out.println(emp);
sqlSession.close();
}
1.2 SQL语句中的参数传递
- SQL语句中的参数
- 固定语法,使用${}方式获取参数
- 基本数据类型及包装类,参数名字任意
- 底层实现,将SQL语句中的参数编译为?占位符
- 底层使用高效安全的PreparedStatement实现
- 能用#不用$
- 使用#的原理是?占位符,而$的原理为直接字符串拼接方式
- $使用在参数传入数据库对象的时候,例如表名,列名字等 (select XX from XX order by 列名)
1.3 根据用户名模糊查询
<select id="selectEmployeeByName" parameterType = "string" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id ,emp_name ,emp_salary from t_emp where emp_id like #{emp_name}
</select>
public void queryEmployeeByName() {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("com.atguigu.mybatis.dao.EmployeeMapper.selectEmployeeByName","'%王%'");
for(User user : list){
System.out.println(user);
}
sqlSession.close();
}
1.4 新增用户数据
<insert id="insertEmployee" parameterType = "com.atguigu.mybatis.entity.Employee">
insert into t_emp values(#{empId},#{empName},${empSalary})
</insert>
public void insertEmployee() {
SqlSession sqlSession = sqlSessionFactory.openSession();
Employee employee = new Employee();
employee.setEmpId(null);
employee.setEmpName("testName");
employee.setEmpSalary(5000D);
int row = sqlSession.insert("com.atguigu.mybatis.dao.EmployeeMapper.insertEmployee",employee);
sqlSession.commit();
sqlSession.close();
}
1.5 获取新增的主键值
1.5.1 数据表主键为自动增长的情况
<insert id="insertEmployee" parameterType = "com.atguigu.pojo.Employee" useGeneratedKeys="true" keyProperty="empId">
insert into t_emp values(#{empId},#{empName},${empSalary})
</insert>
- MyBatis框架提供了insert标签的属性:
- useGeneratedKeys:是否使用自动增长主键
- keyProperty:获取自动增长的主键值,储存在Employee对象的哪个字段中
1.5.2 数据表主键不是自动增长
对于不支持自增型主键的数据库(例如 Oracle),则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用。
<insert id="insertEmployee"
parameterType="com.atguigu.mybatis.beans.Employee"
databaseId="oracle">
<selectKey order="AFTER" keyProperty="id"
resultType="integer">
select 表名_seq.currval from dual
</selectKey>
insert into orcl_employee(id,last_name,email,gender) values(employee_seq.nextval,#{lastName},#{email},#{gender})
</insert>