仓库
文章涉及的代码都将统一存放到此仓库,文章涉及的案例代码存放在包:com.hzchendou.blog.demo.example下
代码地址:Gitee
分支:lesson1
涉及案例:Case1
简介
Mybatis 是一款优秀的持久层框架,使用Mybatis框架,开发者只需要编写SQL语句以及POJO类,Mybatis将自动完成连接管理、事务管理、SQL操作、结果集映射(将ResultSet转化为Java对象)等操作,同时提供高级特性,如:插件、自定义驱动语言等。学习并掌握Mybatis将帮助我们编写高效运行的程序代码。为了更好的学习Mybatis,我们将搭建一个Mybatis项目,只提供Mybatis运行环境,同时使用嵌入式数据库SQLite(方便随时运行案例)。
基础配置
依赖配置
配置Pom文件,加入Mybatis依赖,配置如下:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
引入SQLIte驱动,配置如下:
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.21.0.1</version>
</dependency>
为了更加直观的展示结果,需要引入日志功能(方便打印SQL语句以及相关执行结果),根据官方描述,Mybatis支持以下日志组件:
- SLF4J
- Apache Commons Logging
- Log4j 2
- Log4j (3.5.9 起废弃)
- JDK logging
我们采用SLF4j + Logback日志组合, 配置如下:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
博客案例
Mybatis 是持久层框架,提供数据库操作功能,我们将博客系统作为教学实践案例,后续文章也都围绕博客进行教学实践,博客主要功能是发表文章,文章包含以下两个基础内容:
- 文章
- 作者
文章包含以下属性(尽可能简化):
- id
- 文章标题
- 文章作者
- 文章标签
- 文章状态
作者包含以下属性(尽可能简化):
- id
- 用户名
- 备注
Mybatis博客配置
Mybatis配置文件
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>
<!-- 属性配置,可以在后续配置中使用 -->
<properties>
<property name="username" value=""/>
<property name="password" value=""/>
<property name="url" value="jdbc:sqlite:./src/main/resources/database/sqlite.db"/>
<property name="driver" value="org.sqlite.JDBC"/>
</properties>
<!-- 环境配置,包含数据源以及事务,同时可以使用多环境配置,方便开发测试环境进行切换 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- mapper配置 -->
<mappers>
<mapper resource="mapper/BlogMapper.xml"/>
<mapper resource="mapper/AuthorMapper.xml"/>
</mappers>
</configuration>
数据库表配置
Mybatis是半自动ORM,需要开发者提供SQL语句。数据库中的每一张表对应Mybatis中的三个文件:
- xxxxDO(数据模型,将表记录转化为POJO对象方便程序处理)
- Mapper接口(为Java程序提供SQL操作接口,方便程序调用)
- Mapper XML文件(与Mapper接口对应,为Mapper接口中的每一个方法提供对应的SQL语句)
现在以文章为例,定义DO模型如下:
/**
* 博文DO
*/
@Data
public class BlogDO {
/**
* 文章ID
*/
private Integer id;
/**
* 文章标题
*/
private String title;
/**
* 文章作者Id
*/
private Integer authorId;
/**
* 标签列表
*/
private String tags;
/**
* 文章状态
*/
private Integer status;
}
Mapper接口如下:
/**
* 博文信息Mapper
*/
public interface BlogMapper {
/**
* 查询所有记录
*
* @return
*/
List<BlogDO> selectAll();
/**
* 添加记录
*
* @param blogDO
* @return
*/
int insert(BlogDO blogDO);
}
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.hzchendou.blog.demo.mapper.BlogMapper">
<resultMap id="blogDO" type="com.hzchendou.blog.demo.entity.BlogDO">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="title" jdbcType="VARCHAR" property="title" />
<result column="author_id" jdbcType="INTEGER" property="authorId" />
<result column="tags" jdbcType="VARCHAR" property="tags" />
<result column="status" jdbcType="INTEGER" property="status" />
</resultMap>
<sql id="blog_columns">
id, `title`, `author_id`, `tags`, `status`
</sql>
<!-- 对应Mapp二接口中的 selectAll方法-->
<select id="selectAll" resultMap="blogDO">
SELECT <include refid="blog_columns"/> FROM blog
</select>
<!-- 对应Mapp二接口中的 insert-->
<insert id="insert" parameterType="com.hzchendou.blog.demo.entity.BlogDO" useGeneratedKeys="true" keyProperty="id">
insert into blog(`title`, `author_id`, `tags`, `status`)
values (#{title,jdbcType=VARCHAR}, #{authorId,jdbcType=INTEGER}, #{tags,jdbcType=VARCHAR}, #{status,jdbcType=INTEGER})
</insert>
</mapper>
程序运行
使用上述配置也就完成了Mybatis项目搭建,我们假设要在数据库中创建一篇文章,同时创建文章作者记录:
public void run() throws IOException {
/// 读取配置文件,初始化mybatis
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
/// 创建SqlSession工厂对象,方便后续创建SqlSession,使用SqlSession操作数据库
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
/// 使用Java 7提供的 try-with-resource写法,让JVM自动完成资源关闭操作
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
获取Mapper接口示例(底层使用了JDK的Proxy.newProxyInstance方法创建代理)
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
创建博文记录
BlogDO blog = new BlogDO();
blog.setTitle("时间海绵博文");
blog.setAuthorId(1);
blog.setTags("博文、时间海绵");
blog.setStatus(1);
int res = blogMapper.insert(blog);
log.info("创建时间海绵博文结果: {}", res);
/// 需要提交事务确保提交成功,只有提交了事务才能在数据库中正确插入数据
sqlSession.commit();
查询文章记录
List<BlogDO> blogs = blogMapper.selectAll();
log.info("博文信息列表: {}", blogs);
获取Mapper接口示例(底层使用了JDK的Proxy.newProxyInstance方法创建代理)
AuthorMapper authorMapper = sqlSession.getMapper(AuthorMapper.class);
/// 创建文章作者记录
AuthorDO authorDO = new AuthorDO();
authorDO.setId(1);
authorDO.setUsername("时间海绵");
authorDO.setRemark("不知名博主");
res = authorMapper.insert(authorDO);
log.info("创建时间海绵作者结果: {}", res);
/// 查询所有作者信息
List<AuthorDO> authors = authorMapper.selectAll();
log.info("作者信息列表: {}", authors);
sqlSession.commit();
}
}
运行上述程序,得到如下结果:
使用Slf4j日志组件进行日志初始化,符合预期
15:34:10.195 [main] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
使用数据库连接池方式管理连接
15:34:10.213 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
15:34:10.213 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
15:34:10.213 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
15:34:10.213 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
15:34:10.313 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Opening JDBC Connection
15:34:10.772 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Created connection 1391942103.
注意这里将 autocommit 设置为 false,因此程序中需要显示调用commit方法提交事务,否则SQL更新操作将不成功
15:34:10.772 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [org.sqlite.SQLiteConnection@52f759d7]
插入文章记录
15:34:10.774 [main] DEBUG com.hzchendou.blog.demo.mapper.BlogMapper.insert - ==> Preparing: insert into blog(`title`, `author_id`, `tags`, `status`) values (?, ?, ?, ?)
15:34:10.790 [main] DEBUG com.hzchendou.blog.demo.mapper.BlogMapper.insert - ==> Parameters: 时间海绵博文(String), 1(Integer), 博文、时间海绵(String), 1(Integer)
15:34:10.791 [main] DEBUG com.hzchendou.blog.demo.mapper.BlogMapper.insert - <== Updates: 1
15:34:10.794 [main] INFO com.hzchendou.blog.demo.example.Case1 - 创建时间海绵博文结果: 1
提交事务,对应代码中的 sqlSession.commit()操作
15:34:10.795 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Committing JDBC Connection [org.sqlite.SQLiteConnection@52f759d7]
15:34:10.798 [main] DEBUG com.hzchendou.blog.demo.mapper.BlogMapper.selectAll - ==> Preparing: SELECT id, `title`, `author_id`, `tags`, `status` FROM blog
15:34:10.798 [main] DEBUG com.hzchendou.blog.demo.mapper.BlogMapper.selectAll - ==> Parameters:
15:34:10.808 [main] DEBUG com.hzchendou.blog.demo.mapper.BlogMapper.selectAll - <== Total: 4
15:34:10.809 [main] INFO com.hzchendou.blog.demo.example.Case1 - 博文信息列表: [BlogDO(id=1, title=时间海绵博文, authorId=1, tags=博文、时间海绵, status=1), BlogDO(id=2, title=时间海绵博文, authorId=1, tags=博文、时间海绵, status=1), BlogDO(id=3, title=时间海绵博文, authorId=1, tags=博文、时间海绵, status=1), BlogDO(id=4, title=时间海绵博文, authorId=1, tags=博文、时间海绵, status=1)]
15:34:10.810 [main] DEBUG com.hzchendou.blog.demo.mapper.AuthorMapper.insert - ==> Preparing: insert into author(`username`, `remark`) values (?, ?)
15:34:10.810 [main] DEBUG com.hzchendou.blog.demo.mapper.AuthorMapper.insert - ==> Parameters: 时间海绵(String), 不知名博主(String)
15:34:10.810 [main] DEBUG com.hzchendou.blog.demo.mapper.AuthorMapper.insert - <== Updates: 1
15:34:10.810 [main] INFO com.hzchendou.blog.demo.example.Case1 - 创建时间海绵作者结果: 1
15:34:10.810 [main] DEBUG com.hzchendou.blog.demo.mapper.AuthorMapper.selectAll - ==> Preparing: SELECT id, `username`, `remark` FROM `author`
15:34:10.811 [main] DEBUG com.hzchendou.blog.demo.mapper.AuthorMapper.selectAll - ==> Parameters:
15:34:10.811 [main] DEBUG com.hzchendou.blog.demo.mapper.AuthorMapper.selectAll - <== Total: 3
15:34:10.811 [main] INFO com.hzchendou.blog.demo.example.Case1 - 作者信息列表: [AuthorDO(id=1, username=时间海绵, remark=不知名博主), AuthorDO(id=2, username=时间海绵, remark=不知名博主), AuthorDO(id=3, username=时间海绵, remark=不知名博主)]
15:34:10.811 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Committing JDBC Connection [org.sqlite.SQLiteConnection@52f759d7]
15:34:10.812 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [org.sqlite.SQLiteConnection@52f759d7]
15:34:10.812 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Closing JDBC Connection [org.sqlite.SQLiteConnection@52f759d7]
Pool类型数据源,SQLSession的关闭操作会将使用的connect连接返回到连接池中,方便后续业务继续使用
15:34:10.812 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Returned connection 1391942103 to pool.
总结
我们基于博客案例搭建了一套最基础的Mybatis项目,为此我们做了以下工作:
- 引入基础依赖保障Mybatis能够运行
- mybatis 依赖
- sqlite 驱动依赖
- 日志依赖
- lombok依赖(注解形式编写setter、getter方法)
- Mybatis配置文件
- JDBC事务
- JDBC数据源
- mapper xml文件
- Mapper接口(方便Java程序操作数据库,而不是调用JDBC操作数据库)
- DO数据模型(方便业务使用数据库中的记录,Mybatis将自动完成数据库记录到DO数据模型的映射操作,当然映射规则需要指定,也可以开启默认规则)
- Mapper XML文件(提供SQL,Mapper接口中的方法底层都是调用SQL语句完成数据库操作,这些SQL语句就是在XML文件中定义的,通过命名空间 + id(方法名)的方式进行一一对应)
参考文档
联系方式
技术更新换代速度很快,我们无法在有限时间掌握全部知识,但我们可以在他人的基础上进行快速学习,学习也是枯燥无味的,加入我们学习牛人经验:
QQ:901856121
点击:加群讨论