MyBatis
1.MyBatis的特点
MyBatis是一个优秀的持久层框架,它对JDBC操作数据库的过程进行封装,使开发者只需要关注 SQL
本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、
结果集检索等JDBC繁杂的过程代码。
优点:
1.简单易学:
本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件 + 配置几个sql映射文件,易于学习,易于使用。
2.灵活:
Mybatis不会对应用程序或者数据库的现有设计强加任何影响,sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
3.解除sql与程序代码的耦合:
通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。
4.sql和代码的分离,提高了可维护性。
5.提供丰富且强大的标签:
提供映射标签,支持对象与数据库的orm字段关系映射。
提供对象关系映射标签,支持对象关系组建维护。
提供xml标签,支持编写动态sql。
2.搭建MyBatis项目
先快速搭建一个maven项目,去除不必要的配置
依赖文件配置
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<!-- log4j Mybatis的日志输出组件 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
编写MyBatis中全局配置文件
在src/main/resources目录下创建mybatis-config.xml,作用:配置了数据源、事务等MyBatis运行环境等。
注:如果src/main下面没有resources目录,那么我们手动创建一个,让其成为Resources Root。
<?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 文件的根节点 -->
<configuration>
<!--
environments:多个配置环境;通过default属性可以对多个环境快速切换。
environments default属性的值必须和某个environment的id值一致。
-->
<!-- 和spring整合后 environments配置将废除,了解即可 -->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
数据库SQL
新建一个数据库ssm与表
CREATE TABLE `dept` (
`deptno` int PRIMARY KEY AUTO_INCREMENT,
`dname` varchar(20),
`loc` varchar(40)
);
INSERT INTO `dept` VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO `dept` VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO `dept` VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO `dept` VALUES (40, 'OPERATIONS', 'BOSTON');
CREATE TABLE `emp` (
`empno` int PRIMARY KEY AUTO_INCREMENT,
`ename` varchar(20),
`job` varchar(20),
`mgr` int,
`hiredate` date,
`sal` double,
`comm` double,
`deptno` int,
CONSTRAINT `FK_EMP_DEPTNO` FOREIGN KEY (`deptno`) REFERENCES `dept` (`deptno`)
);
INSERT INTO `emp` VALUES (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 1300,
NULL, 20);
INSERT INTO `emp` VALUES (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 2100,
300, 30);
INSERT INTO `emp` VALUES (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1750,
500, 30);
INSERT INTO `emp` VALUES (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 3475,
NULL, 20);
INSERT INTO `emp` VALUES (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1750,
1400, 30);
INSERT INTO `emp` VALUES (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 3350,
NULL, 30);
INSERT INTO `emp` VALUES (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2950,
NULL, 10);
INSERT INTO `emp` VALUES (7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19', 3500,
NULL, 20);
INSERT INTO `emp` VALUES (7839, 'KING', 'PRESIDENT', NULL, '1981-11-17', 5500,
NULL, 10);
INSERT INTO `emp` VALUES (7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 2000,
0, 30);
INSERT INTO `emp` VALUES (7876, 'ADAMS', 'CLERK', 7788, '1987-05-23', 1600,
NULL, 20);
INSERT INTO `emp` VALUES (7900, 'JAMES', 'CLERK', 7698, '0198-12-31', 1450,
NULL, 30);
INSERT INTO `emp` VALUES (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3500,
NULL, 20);
INSERT INTO `emp` VALUES (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1800,
NULL, 10);
数据插入成功:
编写实体类
实体类作为Mybatis进行sql映射使用,实体类通常与数据库表对应,Emp.java如下:
注:实体类是用来和数据库表对应的,我们最好全部使用引用类型。
import java.util.Date;
public class Emp
{
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
//get,set方法省略
}
编写映射文件
在src/main/resources下创建mapper目录,在该目录下创建sql映射文件Emp.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">
<!--
namespace: 命名空间,作用是mapper文件进行分类管理,用于隔离sql语句。
注意:如果使用mapper代理的方式进行开发,namespace有特殊的作用。
-->
<mapper namespace="emp">
<select id="selectById" parameterType="java.lang.Integer"
resultType="com.wedu.po.Emp">
select empno, ename, job, hiredate, mgr, sal, comm, deptno from emp where
empno=#{empno}
</select>
</mapper>
加载映射文件
在MyBatis的全局配置文件mybatis-config.xml中添加映射文件位置。
<!-- 加载映射文件的位置 -->
<mappers>
<mapper resource="mapper/Emp.xml"/>
</mappers>
log4j配置
Mybatis日志输出:log4j.properties配置文件。
#井号表示注释,配置内容为键值对格式,每行只能有一个键值对,键值对之间以=连接
#指定logger
#设定log4j的日志级别和输出的目的地
#INFO日志级别,Console和logfile输出的目的地
#等级 OFF,ERROR,WARN,INFO,DEBUG,TRACE,ALL
log4j.rootLogger=DEBUG,Console
#指定appender
#设定Logger的Console,其中Console为自定义名称,类型为控制台输出
log4j.appender.Console=org.apache.log4j.ConsoleAppender
#设定Logger的logfile,其中logfile为自定义名称,类型为文件
#org.apache.log4j.FileAppender文件
#org.apache.log4j.RollingFileAppender文件大小到达指定尺寸后产生一个新的文件
#org.apache.log4j.DailyRollingFileAppender每天产生一个日志文件
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
#设定文件的输出路径
log4j.appender.logfile.File=d:/log/test.log
#设定文件最大尺寸 单位可以使KB,MB,GB
log4j.appender.logfile.MaxFileSize=2048KB
#输出格式
#设定appender布局Layout
# %d 输出日志的日期和时间,指定格式:%d{yyyy-MM-dd HH:mm:ss SSS}
# %p 输出的日志级别
# %c 输出所属类的全类名
# %M 方法名
# %m 输出代码中指定消息
# %n 一个换行符
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d %p %c.%M() --%m%n
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p %c.%M() --%m%n
编写测试程序
package com.wedu;
import com.wedu.po.Emp;
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;
public class MybatisTest {
@Test
public void test() throws IOException {
//1.创建读取全局配置文件的流
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//2.通过配置文件流创建会话工厂
SqlSessionFactory factory = builder.build(in);
//3.通过会话工厂创建会话对象(SqlSession)
SqlSession session = factory.openSession();
Emp emp = session.selectOne("emp.selectById", 7369);
System.out.println(emp);
session.close();
}
}
3.增删改查的基本操作
实现以下功能:
1. 查询所有员工信息;
2. 添加员工;
3. 更新员工;
4. 删除员工;
查询操作
mapper文件:
Java代码:
package com.wedu;
import com.wedu.po.Emp;
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.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MybatisTest {
private SqlSession session;
@Before
public void setUp() throws IOException{
//1.创建读取全局配置文件的流
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//2.通过配置文件流创建会话工厂
SqlSessionFactory factory = builder.build(in);
//3.通过会话工厂创建会话对象(SqlSession)
session = factory.openSession();
}
@Test
public void test() throws IOException {
Emp emp = session.selectOne("emp.selectById", 7369);
System.out.println(emp);
}
@Test
public void testSelectAll(){
List<Emp> emps = session.selectList("emp.selectAll");
emps.forEach(System.out::println);
}
@After
public void traeDown(){
session.close();
}
}
新增操作
mapper文件:
测试:
@Test
public void testinsert(){
Emp emp= new Emp();
emp.setEname("张三");
emp.setJob("java");
emp.setSal(500.0);
int count= session.insert("emp.insert",emp);
System.out.println(count);
//mybatis的事务是需要手动提交
session.commit();
}
对应的数据库,一定要手动提交事务,不然没有数据库没有数据
修改
mapper文件:
测试:
@Test
public void testUpdate() throws IOException {
Emp emp = new Emp();
emp.setEmpno(7936);
emp.setEname("JERRY");
emp.setJob("MANAGER");
emp.setMgr(7698);
emp.setHiredate(new Date(new Date().getTime() + 1000*60*60*24));
emp.setSal(7800.0);
emp.setComm(800.0);
int count= session.update("emp.update",emp);
System.out.println(count);
//mybatis的事务是需要手动提交
session.commit();
}
删除操作
mapper文件:
测试:
@Test
public void testDelete() throws IOException {
int result = session.delete("emp.delete", 7936);
System.out.println("影响数据库的条数为:" + result);
session.commit();
}
4. Mapper代理方式
Mapper代理开发方式只需要程序员编写Mapper接口(相当于Dao接口),由MyBatis框架根据接口定
义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
程序员编写Mapper接口需要遵循一些开发规范,MyBatis可以自动生成Mapper接口实现类代理对象。
开发规范
1、Mapper.xml文件中的namespace与mapper接口的类路径相同。
2、Mapper.xml中定义的每个标签的id与Mapper接口方法名相同。
3、Mapper.xml中定义的每个sql的parameterType的类型与Mapper接口方法的参数类型相同。
4、Mapper.xml中定义的每个sql的resultType的类型与Mapper接口方法返回值类型相同。
}
注:Mapper.xml映射文件最好和Mapper接口名称一致。
Mybatis 工具类
为了简化MyBatis的开发,可将MyBatis进一步封装。
package com.wedu.util;
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 java.io.IOException;
import java.io.InputStream;
/**
* Mybatis工具类
*/
public class MybatisUtil {
/**
* 不让用户在外界创建工具类对象
*/
private MybatisUtil() {
}
/**
* 初始化SqlSessionFactory对象
*/
private static SqlSessionFactory factory;
static {
try {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession对象的方法
*/
public static SqlSession getSession() {
return factory.openSession();
}
}
实体类
import java.util.Date;
public class Emp
{
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
//get,set方法省略
}
Mapper接口
- 批量查询:方法返回值为List类型,表示SqlSession对象将调用selectList()方法。
- 单条查询:方法返回值为单个实体对象,表示SqlSession对象将调用selectOne()方法。
- 增删改:
1.方法返回值为void,表示SqlSession对象中insert,update,delete方法的返回值不做任何处理。
2.方法返回值为int类型,表示SqlSession对象中insert,update,delete方法的返回值直接返回。
3.方法返回值为boolean类型,表示根据SqlSession对象中的insert,update,delete方法返回值(影响数据库的条数)判断操作是否成功,如果影响数据库的条数大于0条,表示成功,否则表示失败。
mapper文件
<?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">
<!--namespace:与Mapper接口的全限定名保持一致-->
<mapper namespace="com.wedu.mapper.EmpMapper">
<!--
statementId与Mapper接口的方法名称保持一致;
parameterType的类型必须与方法的参数类型保持一致;
resultType的类型必须与方法的返回值类型保持一致;
-->
<select id="select" resultType="com.wedu.po.Emp">
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp
</select>
<select id="selectById" parameterType="java.lang.Integer"
resultType="com.wedu.po.Emp">
select empno,ename,job,hiredate,mgr,sal,comm,deptno from emp where
empno=#{empno}
</select>
<insert id="insert" parameterType="com.wedu.po.Emp">
insert into emp(ename,job,mgr,hiredate,sal,comm,deptno)
values(#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm},#{deptno})
</insert>
<update id="update" parameterType="com.wedu.po.Emp">
update emp set
ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},sal=#{sal},comm=#{comm},deptno=#{deptno}
where empno=#{empno}
</update>
<delete id="delete" parameterType="java.lang.Integer">
delete from emp where empno=#{empno}
</delete>
</mapper>
加载mapper文件:
测试
package com.wedu;
import com.wedu.po.Emp;
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.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MybatisTest {
private SqlSession session;
@Before
public void setUp() throws IOException{
//1.创建读取全局配置文件的流
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//2.通过配置文件流创建会话工厂
SqlSessionFactory factory = builder.build(in);
//3.通过会话工厂创建会话对象(SqlSession)
session = factory.openSession();
}
@Test
public void test() throws IOException {
Emp emp = session.selectOne("emp.selectById", 7369);
System.out.println(emp);
}
@Test
public void testSelectAll(){
List<Emp> emps = session.selectList("emp.selectAll");
emps.forEach(System.out::println);
}
@Test
public void testinsert(){
Emp emp= new Emp();
emp.setEname("张三");
emp.setJob("java");
emp.setSal(500.0);
int count= session.insert("emp.insert",emp);
System.out.println(count);
//mybatis的事务是需要手动提交
session.commit();
}
@Test
public void testUpdate() throws IOException {
Emp emp = new Emp();
emp.setEmpno(7936);
emp.setEname("JERRY");
emp.setJob("MANAGER");
emp.setMgr(7698);
emp.setHiredate(new Date(new Date().getTime() + 1000*60*60*24));
emp.setSal(7800.0);
emp.setComm(800.0);
int count= session.update("emp.update",emp);
System.out.println(count);
//mybatis的事务是需要手动提交
session.commit();
}
@Test
public void testDelete() throws IOException {
int result = session.delete("emp.delete", 7936);
System.out.println("影响数据库的条数为:" + result);
session.commit();
}
@After
public void traeDown(){
session.close();
}
}
比如运行插入:
Mybatis官方推荐使用mapper代理方式开发mapper接口,程序员不用编写mapper接口实现类,使用
mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。