MyBatis入门

1、MyBatis

1.1、概念

MyBatis 是一个开源的持久层的框架。

1.2、优点

使用 xml 文件将一些参数配置起来,将 jdbc 过程封装起来,使开发者只关注 sql 本身。
程序员自己编写 sql 语句,可控制 sql 语句性能,灵活性高。
使用数据库连接池,解决了 jdbc 频繁连接对数据库资源的浪费。
MyBatis 将 sql 语句配置在 xml 文件中,并将 java 对象和 sql 语句映射生成最终执行的 sql 语句。
解决了原来将 sql 语句写在 java 代码中的硬编码问题。
与 Hibernate 相比,不用考虑复杂的实体间关系问题。

1.3、缺点

不能象 Hibernate 一样自动生成 sql 语句,开发人员工作量大。
数据库无关性差,不能像 Hibernate 一样只需要换驱动,MyBatis 需要重写 sql 语句。

1.4、结构


2、入门案例

2.1、依赖包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<dependencies>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.7</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.8</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.6</version>
</dependency>

<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.18.2-GA</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>5.0.3</version>
</dependency>
</dependencies>

2.2、数据库表

1
2
3
4
5
6
7
CREATE TABLE `linbook` (
`bookid` int(11) NOT NULL,
`bookname` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`booknum` int(11) NULL DEFAULT NULL,
`bookcategory` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`bookid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

2.3、实体类

1
2
3
4
5
6
public class LinBook {
private Integer BookId;
private String BookName;
private Integer BookNum;
private String BookCategory;
}

2.4、Dao 层接口

接口动态开发,可不使用该种开发方法,此方式实现类由动态代理生成。
此种方式要求 BookDao.xml 文件与接口位于同一包下,且文件名相同。
xml 文件中的每一个 sql 语句标签和接口中的一个方法对应。其标签 id 和接口中的方法名相同。
xml 文件中的 namespace 的值与接口全类名相同。

1
2
3
4
5
6
7
8
9
10
11
public interface BookDao {
//使用注解等同于下面的xml文件配置
@Select("select * from linbook where bookid=#{v}")
LinBook getBookById(@Param("v")int bookId);
public LinBook findBookById(Integer id);
public List<LinBook> findBookByName(String name);
public void insertBook(LinBook linbook);
public void updateBook(LinBook linbook);
public void deleteBook(LinBook linbook);
public int count();
}

2.5、BookDao.xml,该 xml 中配置 sql 语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?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:命名空间,用于隔离sql, 命名空间 user.findUserById -->
<mapper namespace="com.lin.dao.BookDao">
<!-- resultMap:定义结果集映射,result:一列 -->
<resultMap type="com.lin.bean.LinBook" id="LinBookResultMap" >
<!-- id:主键;property:主键,column:列名 -->
<id property="BookId" column="bookid" />
<result property="BookNum" column="booknum" />
<result property="BookName" column="bookname" />
<result property="BookCategory" column="bookcategory" />
</resultMap>
<!-- parameterMap :定义参数集映射 -->
<parameterMap type="com.lin.bean.LinBook" id="BookParameterMap">
<parameter property="bookId" resultMap="LinBookResultMap" />
<parameter property="bookNum" resultMap="LinBookResultMap" />
<parameter property="bookName" resultMap="LinBookResultMap" />
<parameter property="bookCategory" resultMap="LinBookResultMap" />
</parameterMap>
<!-- 配置sql语句,parameterType:参数类型;resultType:返回值类型 -->
<!-- #{}:占位符,传入的是值类型或者pojo,不会导致sql注入 -->
<!-- ${}:用于字符串拼接,不会转义,会导致潜在的sql注入,不推荐使用。 -->
<!-- parameterType:参数类型。resultType:返回值类型。statementType:statement类型,STATEMENT,PREPARED,CALLABLE,默认值CALLABLE -->
<!-- useGeneratedKeys="true" keyProperty="id" :配合设置自增主键 -->
<select id="findBookById" parameterType="Integer" resultMap="LinBookResultMap" statementType="PREPARED">
select * from linbook where bookid=#{v}
</select>
<select id="findBookByName" parameterType="String" resultType="com.lin.bean.LinBook">
select * from linbook where bookname like "%"#{v}"%"
</select>
<insert id="insertBook" parameterType="com.lin.bean.LinBook">
insert into linbook values(#{BookId},#{BookName},#{BookNum},#{BookCategory})
</insert>
<update id="updateBook" parameterType="com.lin.bean.LinBook">
update linbook set bookname=#{BookName} where bookid=#{BookId}
</update>
<delete id="deleteBook" parameterType="com.lin.bean.LinBook">
delete from linbook where bookid=#{BookId}
</delete>
<select id="count" resultType="java.lang.Integer">
select count(*) from linbook
</select>
</mapper>

同时可以在其中为 sql 语句配置超时时间,需要在 sqlMapConfig.xml 文件中,加入一段;
也可以在每个 sql 语句标签中独立配置,使用 timeout 属性。

1
2
3
<select id="count" resultType="java.lang.Integer" timeout="10000" >
select count(*) from linbook
</select>

2.6、sqlMapConfig.xml 配置文件,位于项目根目录下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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>
<!-- 此处为全局属性配置 -->
<settings>
<!-- 配置sql语句默认超时时间 -->
<setting name="defaultStatementTimeout" value="10000" />
</settings>
<environments default="development">
<environment id="development">
<!-- 事务管理 -->
<!-- JDBC:使用jdbc提供的事务控制 -->
<!-- MANAGE:使用容器提供的事务控制,MyBatis自己不提供事务控制 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://192.168.20.40:3306/swan?characterEncoding=utf-8" />
<property name="username" value="devswan" />
<property name="password" value="DEVswan123!" />
</dataSource>
</environment>
</environments>
<!-- 引入sql语句映射 -->
<mappers>
<!-- 三种方式,任选其一 -->
<mapper resource="com/lin/dao/BookDao.xml" />
<!-- 批量加载该包下的所有映射文件,且文件名与接口名相同,位于同一位置 -->
<!-- <package name="com.lin.dao" /> -->
<!-- 要求文件名与接口名相同,位于同一位置 -->
<!-- <mapper class="com.lin.dao.BookDao" /> -->
</mappers>
</configuration>

2.7、日志配置

1
2
3
4
5
6
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

2.8、测试类

有两种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void testMybatis1() {
String resource = "sqlMapConfig.xml";
try {
//以流的方式拿到配置文件
InputStream resourceAsStream = Resources.getResourceAsStream(resource);
//创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//创建SqlSession
SqlSession session = sqlSessionFactory.openSession();
//~~1~~执行Sql语句
LinBook book = session.selectOne("com.lin.dao.BookDao.findBookById", 1);
//~~2~~拿到Dao层对象,调用方法执行sql语句
BookDao bookDao = session.getMapper(BookDao.class);
LinBook Book = bookDao.findBookById(1);
//更新,插入,删除操作后需要进行事务提交
session.commit();
System.out.println(book);
} catch (IOException e) {
e.printStackTrace();
}
}

第一种方式:来源于 MyBatis 的前身 iBatis
第二种方式:getMapper()方法,通过动态代理的方法,拿到接口的实例,再调用方法。