1. Mybatis架构
1.1 基本概念
- mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。 - 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。 - mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
- Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
- Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
- Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
2 Mybatis入门程序
- mybaits的代码由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases
- mybatis-3.2.7.jar—-mybatis的核心包
- lib—-mybatis的依赖包
- mybatis-3.2.7.pdf—-mybatis使用手册
2.1 导入jar包
- 加入mybatis核心包、依赖包、数据驱动包。
2.2 编写log4j.properties文件
# 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.3 编写SqlMapConfig.xml文件
<?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>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理-->
<transactionManager type="JDBC" />
<!-- 数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
</configuration>
SqlMapConfig.xml是mybatis核心配置文件,上边文件的配置内容为数据源、事务管理。
2.4 po类
Public class User {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
//....
}
2.5 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="test">
</mapper>
2.6 加载映射文件
<!-- 引入配置文件 -->
<mappers>
<!-- <mapper resource="User.xml"/> -->
<!-- 使用class属性引入接口的全路径名称
使用规则:
1.接口的名称和映射文件名称除扩展名外
2.接口和映射文件要放在同一个目录下
-->
<!-- <mapper class="com.dml.mapper.UserMapper"/> -->
<!-- 使用包扫描的方式批量引入 Mapper接口
使用规则:
1.接口的名称和映射文件名称除扩展名外
2.接口和映射文件要放在同一个目录下
-->
<package name="com.dml.mapper"/>
</mappers>
2.7 根据id查询用户信息
在user.xml中添加:
<!-- 根据id获取用户信息 -->
<!--
id:sql语句唯一标识符
parameterType:指定传入参数类型
resultType:返回结果集类型
#{}:占位符:起到占位作用,如果传入的是基本类型(String,long,double,boolean,float等)
那么#{}中的变量名称可以任意写
-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.dml.pojo.User">
select * from user where id=#{id}
</select>
测试程序
public class Mybatis_first {
//会话工厂
private SqlSessionFactory sqlSessionFactory;
@Before
public void createSqlSessionFactory() throws IOException {
// 配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 使用SqlSessionFactoryBuilder从xml配置文件中创建SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
}
// 根据 id查询用户信息
@Test
public void testFindUserById() {
// 数据库会话实例
SqlSession sqlSession = null;
try {
// 创建数据库会话实例sqlSession
sqlSession = sqlSessionFactory.openSession();
// 查询单个记录,根据用户id查询用户信息
第一个参数:所调用的sql语句=namespace.sql的id
User user = sqlSession.selectOne("test.findUserById", 10);
// 输出用户信息
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
2.8 根据用户名查询用户信息
在user.xml中添加:
<!-- 自定义条件查询用户列表 -->
<!-- 如果返回结果集合,可以调用selectList方法,这个方法返回的结果就是一个集合,
所以映射文件中应该配置成集合泛型的类型
select * from user where username like #{name}
${}拼接符:字符串原样拼接,如果传入的参数是基本类型(String,long,double,boolean,float等)
那么${}中的变量名称必须是value
注意:拼接符有sql注入风险,所以慎重使用
-->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.dml.pojo.User">
select * from user where username like '%${value}%'
</select>
测试程序
// 根据用户名称模糊查询用户信息
@Test
public void testFindUserByUsername() {
// 数据库会话实例
SqlSession sqlSession = null;
try {
// 创建数据库会话实例sqlSession
sqlSession = sqlSessionFactory.openSession();
// 查询单个或多个记录,根据用户name查询用户信息,所以使用selectList
List<User> list = sqlSession.selectList("test.findUserByName", "张");
System.out.println(list.size());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
2.9 添加用户
映射文件User.xml
<!-- 插入数据
#{}:如果传入的是pojo类型,那么#{}中的变量名称必须是pojo中对应的属性.属性.属性
如果要返回数据库自增主键:可以使用select LAST_INSERT_ID()
-->
<insert id="insertUser" parameterType="com.dml.pojo.User" >
<!-- 执行select LAST_INSERT_ID()数据库函数,返回自增的主键
keyProperty:将返回的主键放入传入参数的id中保存
order:当前函数相对于insert语句的执行顺序
resultType:id的类型,也就是keyProperty属性的类型
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
测试程序
// 添加用户信息
@Test
public void testInsert() {
// 数据库会话实例
SqlSession sqlSession = null;
try {
// 创建数据库会话实例sqlSession
sqlSession = sqlSessionFactory.openSession();
// 添加用户信息
User user = new User();
user.setUsername("嘟嘟");
user.setBirthday(new Date());
user.setSex("1");
user.setAddress("广西柳州");
sqlSession.insert("test.insertUser", user);
//提交事务mybatis会自动开启事务,所以需要手动提交
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
2.10 Mysql使用 uuid实现主键
需要增加通过select uuid()得到uuid值
<insert id="insertUser" parameterType="com.dml.pojo.User">
<selectKey resultType="java.lang.String" order="BEFORE"
keyProperty="id">
select uuid()
</selectKey>
insert into user(id,username,birthday,sex,address)
values(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
注意这里使用的order是“BEFORE”
2.11 删除用户
映射文件
<!-- 删除 -->
<delete id="delUserById" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
测试程序
// 根据id删除用户
@Test
public void testDelete() {
// 数据库会话实例
SqlSession sqlSession = null;
try {
// 创建数据库会话实例sqlSession
sqlSession = sqlSessionFactory.openSession();
// 删除用户
sqlSession.delete("test.delUserById",18);
// 提交事务
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
2.12 修改用户
映射文件
<!-- 更新 -->
<update id="updateUserById" parameterType="com.dml.pojo.User">
update user set username=#{username} where id=#{id}
</update>
测试程序
@Test
public void testUpdate() {
// 数据库会话实例
SqlSession sqlSession = null;
try {
// 创建数据库会话实例sqlSession
sqlSession = sqlSessionFactory.openSession();
// 添加用户信息
User user = new User();
user.setUsername("哈哈");
user.setId(26);
sqlSession.update("test.updateUserById", user);
// 提交事务
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
Mybatis解决jdbc编程的问题
- 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。 - Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。 - 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。 - 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。
User.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:命名空间,做sql隔离 -->
<mapper namespace="test">
<!--
id:sql语句唯一标识符
parameterType:指定传入参数类型
resultType:返回结果集类型
#{}:占位符:起到占位作用,如果传入的是基本类型(String,long,double,boolean,float等)
那么#{}中的变量名称可以任意写
-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.dml.pojo.User">
select * from user where id=#{id}
</select>
<!-- 如果返回结果集合,可以调用selectList方法,这个方法返回的结果就是一个集合,
所以映射文件中应该配置成集合泛型的类型
select * from user where username like #{name}
${}拼接符:字符串原样拼接,如果传入的参数是基本类型(String,long,double,boolean,float等)
那么${}中的变量名称必须是value
注意:拼接符有sql注入风险,所以慎重使用
-->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.dml.pojo.User">
select * from user where username like '%${value}%'
</select>
<!-- 插入数据
#{}:如果传入的是pojo类型,那么#{}中的变量名称必须是pojo中对应的属性.属性.属性
如果要返回数据库自增主键:可以使用select LAST_INSERT_ID()
-->
<insert id="insertUser" parameterType="com.dml.pojo.User" >
<!-- 执行select LAST_INSERT_ID()数据库函数,返回自增的主键
keyProperty:将返回的主键放入传入参数的id中保存
order:当前函数相对于insert语句的执行顺序
resultType:id的类型,也就是keyProperty属性的类型
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 删除 -->
<delete id="delUserById" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
<!-- 更新 -->
<update id="updateUserById" parameterType="com.dml.pojo.User">
update user set username=#{username} where id=#{id}
</update>
</mapper>
SqlMapConfig.xml文件
<?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 resource="db.properties"></properties>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理-->
<transactionManager type="JDBC" />
<!-- 数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 引入配置文件 -->
<mappers>
<mapper resource="User.xml"/>
</mappers>
</configuration>
db.properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root