1 本章前言
在上一章简单介绍了什么是 Mybatis,它封装的有哪些重要的组件以及它的使用步骤,所以这一章就来编写一个 Mybatis 的入门实例。首先说明一点:MyBatis 的使用分为三个版本:
- 基于原生接口的 XML 版本。
- 基于 Mapper 接口的 XML 版本。
- 基于 Java 注解版本。
一般推荐基于 Mapper 接口和基于 Java 注解的方式,因为这两种方式在实际开发中我们更加常用。但是现在这里只是刚刚入门,所以就用原生接口的 XML 版本来创建一个 Mybatis 的入门实例。看看如何实现对数据库的基本操作,其步骤如下。
2 创建一个数据库
由于 Mybatis 是对数据库的操作,所以首先得先创建一个数据库和一个表,数据库命名为 mybatis,表命名为 t_user。这里针对 MySQL 数据库。SQL 脚本如下:
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`age` int(11) NULL DEFAULT NULL,
`sex` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES (1, '奥利给', 18, '男', '上海');
INSERT INTO `t_user` VALUES (2, '蔡徐坤', 18, '男', '北京');
INSERT INTO `t_user` VALUES (3, '黄飞鸿', 42, '男', '大清');
INSERT INTO `t_user` VALUES (4, '十三姨', 18, '女', '大清');
INSERT INTO `t_user` VALUES (5, '梁宽', 42, '男', '大清');
INSERT INTO `t_user` VALUES (6, '马保国', 33, '男', '深圳');
INSERT INTO `t_user` VALUES (7, '纳兰元述', 42, '男', '大清');3 创建 Maven 工程
在 Eclipse 或 IDEA 中创建一个 Maven 项目。

设置 jar 打包方式
<groupId>org.wsc</groupId>
<artifactId>MaBatis1</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>导入 maven 依赖
<dependencies>
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!-- 日志处理 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>4 编写 User 实体类
创建一个 User 实体类,这里省略了 getter、setter 和 toString 方法,需自己加上。
@Data
public class User {
private Integer id;
private String username;
private Integer age;
private String sex;
private String address;
}5 创建 Mybatis 全局配置文件
习惯上命名为
mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。将来整合 Spring 之后,这个配置文件可以省略,所以大家操作时可以直接复制、粘贴。
核心配置文件主要用于配置连接数据库的环境以及 MyBatis 的全局配置信息
核心配置文件存放的位置是 src/main/resources 目录下
<?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">
<!-- id属性必须和上面的default一致 -->
<environment id="development">
<!--配置事务的类型-->
<transactionManager type="JDBC"/>
<!--dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象源 -->
<dataSource type="POOLED">
<!--配置连接数据库的4个基本信息-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/user?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>对 mybatis-config.xml 中配置项的简单说明:
environments:配置当前的环境,default 属性为当前使用的环境配置 ID。environment:配置每个 environment 定义的环境,可以配置多个运行环境,但是每个 SqlSessionFactory 实例只能选择一个运行环境。id 属性为环境 ID。如果配置了两个相同的 environment,Mybatis 会用后面的覆盖掉前面的。transactionManager:配置事务管理器类型,type 属性中有 JDBC 和 MANAGED 两种,一次只能配置一个。JDBC使用 JdbcTransactionFactory 工厂生成的 JdbcTransaction 对象实现,以 JDBC 的方式进行数据库的提交、回滚等操作,它依赖于从数据源得到的连接来管理事务范围。MANAGED使用 ManagedTransactionFactory 工厂生成的 ManagedTransaction 对象实现,它的提交和回滚不需要任何操作,而是把事务交给容器进行处理,默认情况下会关闭连接。如果不希望默认关闭,只要将其中的 closeConnection 属性设置为 false 即可。
dataSource:配置数据源类型,type 属性有 UNPOOLED、POOLED 和 JNDI 三种选择:UNPOOLED(UnpooledDataSourceFactory):采用非数据库池的管理方式,每次请求都会新建一个连接,并用完后关闭它,所以性能不是很高。该方式适用于只有小规模数量并发用户的简单应用程序上。POOLED(PooledDataSourceFactory):采用连接池的概念将数据库链接对象 Connection 组织起来,可以在初始化时创建多个连接,使用时直接从连接池获取,避免了重复创建连接所需的初始化和认证时间,从而提升了效率,所以这种方式比较适合对性能要求高的应用中。在开发或测试环境中经常用到此方式。JNDI(JndiDataSourceFactory):数据源 JNDI 的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。在生产环境中优先考虑这种方式。
property:dataSource 中的 property 元素就是数据库相关的配置信息。
6 编写 SQL 映射配置文件
我们在目录 resources-⇒mapper (mapper 目录自行创建) 下创建一个 UserMapper.xml 文件。Mybatis 中所有数据库的操作都会基于该映射文件配置的 SQL 语句,在这个配置文件中可以配置任何类型的 SQL 语句。框架会根据配置文件中的参数配置,完成对 SQL 语句输入输出参数的映射配置。
注意事项 (非常重要!非常重要!非常重要!):
| 相关属性 | 描述 |
|---|---|
| namespace | 表示命名空间,用来设定当前 Mapper 配置文件的唯一标识,将来在 Java 程序中通过 namespace 属性的值来定位到这个配置文件,namespace 属性值设置的方式:名字可以随便取, 但是推荐以相对应的 Mapper 接口的全类名, 例如 com.thr.mapper.UserMapper |
| id | SQL 映射语句的唯一标识,称为 statement 的 id,将 SQL 语句封装到 mappedStatement 对象中,所以将 id 称为 statement 的 id |
| parameterType | 指定输入参数的类型 |
| resultType | 指定输出结果类型。Mybatis 将 sql 查询结果的一行记录数据映射为 resultType 指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到 List 容器中,后面会还会介绍 resultMap,推荐使用它 |
#{value} | #{value} 表示 SQL 语句的占位符,相当于 JDBC 中的”?”它会自动进行 java 类型和 jdbc 类型转换, #{value}里面参数写啥都可以,但是不要空着,如 #{Id},#{name}。#{value} 可以接收简单类型值或 pojo 属性值。如果 parameterType 传输单个简单类型值,#{} 括号中可以是 value 或其它名称。#{value} 可以有效防止 SQL 注入 |
${value} | ${value} 表示拼接 SQL 字符串,将接收到的参数在不进行 jdbc 类型转换的情况下拼接在 SQL 语句中,${value} 里面必须要写参数,不然会报错。${} 可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${} 括号中只能是 value。使用 ${value} 会造成 SQL 注入,所以尽量不要使用它 |
文件代码如下所示:
记得根据实际对象的全类名路径进行修改。
<?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属性:表示命名空间,用来设定当前Mapper配置文件的唯一标识,将来在Java程序中通过namespace属性的值来定位到这个配置文件 -->
<!-- namespace属性值设置的方式:名字可以随便取,但是推荐以相对应的Mapper接口的全类名,例如com.thr.mapper.UserMapper -->
<mapper namespace="com.thr.mapper.UserMapper">
<!-- 查询所有用户 -->
<select id="selectAllUser" resultType="com.thr.entity.User">
select * from t_user;
</select>
<!-- 通过Id查询一个用户 -->
<select id="selectUserById" parameterType="int" resultType="com.thr.entity.User">
select * from t_user where id = #{id};
</select>
<!-- 模糊查询,根据username字段查询用户-->
<select id="selectUserByName" parameterType="int" resultType="com.thr.entity.User">
select * from t_user where username like '%${value}%';
</select>
<!-- 添加用户-->
<insert id="insertUser" parameterType="com.thr.entity.User">
insert into t_user(username, age, sex, address)
values (#{username}, #{age}, #{sex}, #{address});
</insert>
<!-- 根据Id更新用户 -->
<update id="updateUser" parameterType="com.thr.entity.User">
update t_user set username = #{username},
age = #{age},sex = #{sex},address = #{address} where id = #{id}
</update>
<!-- 根据Id删除用户 -->
<delete id="deleteUser" parameterType="int">
delete from t_user where id = #{id}
</delete>
</mapper>加载配置文件
将上面创建的 UserMapper.xml 文件添加至全局配置文件 mybatis-config.xml 下。
...
</envrioments>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>7 导入日志文件
导入日志文件,在 resources 目录中创建 log4j. Properties 文件,并且导入如下配置(如果 log 报错则以管理员的方式启动 Eclipse 或 IDEA)。
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=D:/axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n8 编写测试代码
最后创建一个 MybatisTest 的测试类,其源代码如下所示:
注意:使用 JDBC 的事务管理在进行增删改操作时,需要进行提交事务,也就是
sqlSession.commit(),否则数据不会操作成功。
public class MybatisTest {
//定义 SqlSession
SqlSession sqlSession = null;
@Before
public void getSqlSession() {
//加载 mybatis 全局配置文件
// 或者 Resources.getResourceAsStream(config);
InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
//创建 SqlSessionFactory 对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//根据 sqlSessionFactory 产生 session
sqlSession = sqlSessionFactory.openSession();
}
@Test
public void testSelectAllUser() {
/**
* 注意:这个字符串由 UserMapper.xml 文件中的两个部分构成(namespace + id)
* <mapper namespace="com.thr.mapper.UserMapper">中 namespace 的值
* <select id="selectAllUser" > 中的 id 值
* 这样 Mybatis 才能找到需要的 SQL
*/
String statement = "com.thr.mapper.UserMapper.selectAllUser";
List<User> listUser = sqlSession.selectList(statement);
for (User user : listUser) {
System.out.println(user);
}
sqlSession.close();
}
//根据 Id 查询一个用户数据
@Test
public void testSelectUserById() {
String statement = "com.thr.mapper.UserMapper.selectUserById";
User user = sqlSession.selectOne(statement, 1);
System.out.println(user);
sqlSession.close();
}
//模糊查询:根据 user 表的 username 字段
@Test
public void testSelectUserByName() {
String statement = "com.thr.mapper.UserMapper.selectUserByName";
List<User> listUser = sqlSession.selectList(statement, "三");
for (User user : listUser) {
System.out.println(user);
}
sqlSession.close();
}
//添加一个用户数据
@Test
public void testInsertUser() {
String statement = "com.thr.mapper.UserMapper.insertUser";
User user = new User();
user.setUsername("张三");
user.setAge(34);
user.setSex("男");
user.setAddress("中国深圳");
int i = sqlSession.insert(statement, user);
System.out.println((i>0)? "添加成功!":"添加失败!");
//提交插入的数据
sqlSession.commit();
sqlSession.close();
}
//根据 Id 修改用户数据
@Test
public void testUpdateUser(){
//如果设置的 id 不存在,那么数据库没有数据更改
String statement = "com.thr.mapper.UserMapper.updateUser";
User user = new User();
user.setId(3);
user.setUsername("王红");
user.setAge(26);
user.setSex("女");
user.setAddress("中国上海");
int i = sqlSession.update(statement, user);
System.out.println( (i>0)? "修改成功!":"修改失败!");
//提交数据
sqlSession.commit();
sqlSession.close();
}
//根据 Id 删除用户数据
@Test
public void testDeleteUser(){
String statement = "com.thr.mapper.UserMapper.deleteUser";
int i = sqlSession.delete(statement, 4);
System.out.println( (i>0)? "删除成功!":"删除失败!");
sqlSession.commit();
sqlSession.close();
}
}