一、Mybatis相关概念
-
对象 / 关系数据库映射(ORM)
- ORM全称 Object Relation Mapping:表示对象 - 关系映射的缩写
- ORM完成⾯向对象的编程语⾔到关系数据库的映射
当ORM框架完成映射后,程序员既可以利⽤⾯向对象程序设计语⾔的简单易⽤性,⼜可以利⽤关系数据库的技术优势。 - ORM把关系数据库包装成⾯向对象的模型
ORM框架是⾯向对象设计语⾔与关系数据库发展不同步时的中间解决⽅案。采⽤ORM框架后,应⽤程序不再直接访问底层数据库,⽽是以⾯向对象的形式来操作持久化对象,⽽ORM框架则将这些⾯向对象的操作转换成底层SQL操作 - ORM框架实现的效果:把对持久化对象的保存、修改、删除等操作,转换为对数据库的操作
-
Mybatis简介
- MyBatis是⼀款优秀的基于ORM的半⾃动轻量级持久层框架,它⽀持定制化SQL、存储过程以及⾼级映射
- MyBatis避免了⼏乎所有的JDBC代码和⼿动设置参数以及获取结果集
- MyBatis可以使⽤简单的XML或注解来配置和映射原⽣类型、接⼝和Java的POJO (Plain Old Java Objects,普通⽼式Java对 象)为数据库中的记录。
-
Mybatis历史
- 原是 apache 的⼀个开源项⽬ iBatis
- 2010年6⽉这个项⽬由apache software foundation 迁移到了google code,随着开发团队转投Google Code旗下,ibatis3.x正式更名为Mybatis ,代码于2013年11
⽉迁移到Github - iBATIS⼀词来源于“internet”和“abatis”的组合,是⼀个基于Java的持久层框架
- iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)
-
Mybatis优势
Mybatis是⼀个半⾃动化的持久层框架,对开发⼈员开说,核⼼sql还是需要⾃⼰进⾏优化,sql和java编码进⾏分离,功能边界清晰,⼀个专注业务,⼀个专注数据
二、Mybatis基本应用
-
快速入门
- MyBatis官⽹地址:http://www.mybatis.org/mybatis-3/
- 开发步骤
- 添加MyBatis的坐标
- 创建user数据表
- 编写User实体类
- 编写映射文件 UserMapper.xml
- 编写核心文件 SqlMapConfig.xml
- 编写测试类
- 环境搭建
- 导⼊MyBatis的坐标和其他相关坐标
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.wujun</groupId> <artifactId>mybatis_quick_start</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding> <java.version>11</java.version> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <org.mybatis.mybatis>3.4.5</org.mybatis.mybatis> <mysql.mysql-connector-java>5.1.6</mysql.mysql-connector-java> <org.projectlombok.lombok.version>1.18.10</org.projectlombok.lombok.version> <com.alibaba.fastjson>1.2.4</com.alibaba.fastjson> <junit.junit>4.12</junit.junit> <log4j.log4j>1.2.12</log4j.log4j> </properties> <!--引入依赖--> <dependencies> <!--mybatis坐标--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${org.mybatis.mybatis}</version> </dependency> <!--mysql驱动坐标--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.mysql-connector-java}</version> <scope>runtime</scope> </dependency> <!--单元测试坐标--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.junit}</version> </dependency> <!--⽇志坐标--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.log4j}</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${org.projectlombok.lombok.version}</version> <scope>provided</scope> </dependency> <!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${com.alibaba.fastjson}</version> </dependency> </dependencies> </project>
- 创建user数据表
CREATE TABLE `user` ( `id` bigint(20) NOT NULL, `username` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`) )
- 编写User实体
package com.wujun.pojo; import lombok.Data; @Data public class User { private Long id; private String username; }
- 编写映射文件 UserMapper.xml
mapper标签的加载方式有4种:- 使用相对于类路径的资源引用
例如:<mapper resource="org/mybatis/builder/AuthorMapper.xml"/> - 使⽤完全限定资源定位符(URL)
例如:<mapper url="file:///var/mappers/AuthorMapper.xml"/> - 使⽤映射器接口实现类的完全限定类名
例如:<mapper class="org.mybatis.builder.AuthorMapper"/> - 将包内的映射器接⼝实现全部注册为映射器
例如:<package name="org.mybatis.builder"/>
- 使用相对于类路径的资源引用
<?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:名称空间,与id组成sql的唯一标识--> <mapper namespace="user"> <select id="findAll" resultType="com.wujun.pojo.User"> select * from User </select> </mapper>
- 编写核心文件 SqlMapConfig.xml
- 事务管理器(transactionManager)类型有两种:
- JDBC:这个配置就是直接使⽤了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域
- MANAGED:这个配置几乎没做什么,它从来不提交或回滚⼀个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应⽤服务器的上下文)。 默认情况下它会关闭连接,然而⼀些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为
- 数据源(dataSource)类型有三种
- UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接
- POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来
- JNDI:这个数据源的实现是为了能在如 EJB 或应⽤服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置⼀个 JNDI 上下文的引用
- 事务管理器(transactionManager)类型有两种:
<?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:运行环境 --> <environments default="dev"> <!-- 一个environment代表一个环境,可以配置多个环境,例如[dev][test][prod]--> <environment id="dev"> <!--当前事务交由JDBC进行管理--> <transactionManager type="JDBC"></transactionManager> <!-- POOLED表示当前使用mybatis提供的数据库连接池 UNPOOLED表示不使用连接池,每次请求都会新建一个数据库连接 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///wujun_test"/> <property name="username" value="wujun"/> <property name="password" value="wujun@2020"/> </dataSource> </environment> </environments> <!-- 引入映射配置文件 --> <mappers> <mapper resource="UserMapper.xml"></mapper> </mappers> </configuration>
- 编写测试类
package com.wujun.test; import com.wujun.pojo.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 test1() throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> users = sqlSession.selectList("user.findAll"); for (User user : users) { System.out.println(user); } sqlSession.close(); } }
- 返回结果
User(id=1, username=吴俊1) User(id=2, username=吴俊2) User(id=3, username=吴俊3)
三、注意事项
执行方法SqlSession sqlSession = sqlSessionFactory.openSession();
的时候,会默认开启一个事务,但是不会自动提交该事务,在执行增删改操作的时候,需要手动提交事务sqlSession.commit();
如果不想手动提交事务,则可以使用SqlSession sqlSession = sqlSessionFactory.openSession(true);
方法,该方法会自动提交事务。
四、Mybatis的Dao层传统开发方式
- 编写Dao层接口
package com.wujun.dao;
import com.wujun.pojo.User;
import java.io.IOException;
import java.util.List;
public interface IUserDao {
List<User> findAll() throws IOException;
}
- 编写Dao层实现类
package com.wujun.dao;
import com.wujun.pojo.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserDaoImpl implements IUserDao {
@Override
public List<User> findAll() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> users = sqlSession.selectList("user.findAll");
sqlSession.close();
return users;
}
}
- 编写测试类
package com.wujun.test;
import com.wujun.dao.IUserDao;
import com.wujun.dao.UserDaoImpl;
import com.wujun.pojo.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 test1() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> users = sqlSession.selectList("user.findAll");
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}*/
@Test
public void test2() throws IOException {
IUserDao userDao = new UserDaoImpl();
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
}
- 测试结果
User(id=1, username=吴俊1)
User(id=2, username=吴俊2)
User(id=3, username=吴俊3)
五、Mybatis的Dao层代理开发方式
-
代理开发方式介绍
- 采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是主流。
- Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法
- Mapper 接⼝开发需要遵循以下规范
- Mapper.xml文件中的namespace与mapper接口的全限定名相同
- Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
- Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
- Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
- 编写 UserMapper 接⼝
public interface UserMapper {
List<User> findAll();
User findById(Long id);
}
- 重写 UserMapper.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:名称空间,与id组成sql的唯一标识-->
<mapper namespace="com.wujun.mapper.UserMapper">
<select id="findAll" resultType="com.wujun.pojo.User">
select * from User
</select>
<select id="findById" parameterType="java.lang.Long" resultType="com.wujun.pojo.User">
select * from User where id = #{id}
</select>
</mapper>
- 编写测试类
package com.wujun.test;
import com.wujun.dao.IUserDao;
import com.wujun.dao.UserDaoImpl;
import com.wujun.mapper.UserMapper;
import com.wujun.pojo.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 test1() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> users = sqlSession.selectList("user.findAll");
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}*/
/*@Test
public void test2() throws IOException {
IUserDao userDao = new UserDaoImpl();
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}*/
@Test
public void test3() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> all = mapper.findAll();
for (User user : all) {
System.out.println(user);
}
System.out.println("===============================");
User byId = mapper.findById(1L);
System.out.println(byId);
}
}
- 测试结果
User(id=1, username=吴俊1)
User(id=2, username=吴俊2)
User(id=3, username=吴俊3)
===============================
User(id=1, username=吴俊1)
网友评论