mybatis 简单入门
mybatis 的简单概述
- mybatis 本是 apache 的一个开源项目 iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
- mybatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。
- mybatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
原生 jdbc 的问题
- 数据库的频繁连接、释放造成资源浪费,影响系统性能(使用数据库连接池来解决此问题)
- sql语句的多变化造成代码变化,不易维护
- sql语句使用硬编码,不易维护
- 对结果集的解析也存在硬编码,不易维护
mybatis 架构解析
- mybatis 配置
- SqlMapConfig.xml
mybatis 全局配置文件,配置mybatis的运行环境等信息 - mapper.xml
sql 映射文件,配置操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载
- SqlMapConfig.xml
- 通过mybatis配置信息构造SqlSessionFactory,即会话工厂
- 通过会话工厂SqlSessionFactory创建会话SqlSession
- mybatis底层自定义了Executor执行器接口来操作数据库,Executor接口有2个实现:基本执行器、缓存执行器
- Mapped Statement也是mybatis底层的一个封装对象,它包装了mybatis的配置信息和sql的映射信息。mapper.xml文件中的一个sql对应一个Mapped Statement,sql的id也即Mapped Statement的id
- Mapped Statement对sql的执行参数进行了定义。Executor通过Mapped Statement在执行sql前将java对象映射到sql中
- Mapped Statement对sql的执行结果也进行了定义。Executor通过Mapped Statement在执行结果映射到java对象中。
mybatis 入门程序
- 引入jar包
- 配置log4j.properties
mybatis 默认使用log4j来输出日志信息
# 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
- 配置 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"/>
<!-- 数据库连接池,使用mybatis自带的连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8" />
<property name="username" value="username" />
<property name="password" value="password" />
</dataSource>
</environment>
</environments>
<!-- 加载mapper.xml -->
<mappers>
<!-- 指定classpath下的文件 -->
<mapper resource="sqlmap/User.xml"/>
</mappers>
</configuration>
- 配置 sqlmap/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">
<!-- 查询 #{}:就相当于一个占位符;如果parameterType传入的是简单类型的值,{}中可以使用value或者其他任意字符,目的是防止sql注入 -->
<select id="findUserById" parameterType="int" resultType="cn.ade.mybatis.po.User">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 查询 ${}:就相当于一个拼接符;如果parameterType传入的是简单类型的值,{}中只能使用value -->
<select id="findUserByUsername" parameterType="string" resultType="cn.ade.mybatis.po.User">
SELECT * FROM user WHERE username LIKE "%${value}%"
</select>
<!-- 新增 -->
<insert id="insertUser" parameterType="cn.ade.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO user VALUES (null, #{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
- 在 SqlMapConfig.xml 中配置 mappers
配置见如上 - 测试程序
public class TestDemo01 {
/** 会话工厂 */
private SqlSessionFactory factory;
@Before
public void createSqlSessionFactory() throws IOException {
// mybatis全局配置文件
String resource = "SqlMapConfig.xml";
// 构造全局配置文件的输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建SqlSessionFactory会话工厂
factory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void findUserById() throws IOException {
// 创建session会话
SqlSession session = factory.openSession();
// 根据session查询用户
User user = session.selectOne("test.findUserById", 1);
System.out.println(user);
// 关闭session
session.close();
}
@Test
public void findUserByUsername() throws IOException {
// 创建会话
SqlSession session = factory.openSession();
// 根据session查询用户
List<User> users = session.selectList("test.findUserByUsername", "五");
System.out.println(users);
// 关闭会话
session.close();
}
@Test
public void insertUser() throws IOException {
// 创建会话
SqlSession session = factory.openSession();
// 添加用户
User user = new User();
user.setUsername("张三");
user.setSex("10");
user.setBirthday(new Date());
user.setAddress("西安");
session.insert("test.insertUser", user);
System.out.println(user.getId());
// 提交事务
session.commit();
// 关闭会话
session.close();
}
}
案例总结
主键问题
- mysql 的主键自增
<!-- 新增 -->
<insert id="insertUser" parameterType="cn.ade.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO user VALUES (null, #{username},#{birthday},#{sex},#{address})
</insert>
keyProperty:返回的主键存储在哪个属性中
order:selectKey的执行顺序
LAST_INSERT_ID():mysql的函数,返回自增列新记录的id值
- oracle 的主键自增
<!-- 新增 -->
<insert id="insertUser" parameterType="cn.ade.mybatis.po.User">
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.Integer">
SELECT 自定义序列.NEXTVAL FROM DUAL
</selectKey>
INSERT INTO user VALUES (null, #{username},#{birthday},#{sex},#{address})
</insert>
- mysql 的uuid
<!-- 新增 -->
<insert id="insertUser" parameterType="cn.ade.mybatis.po.User">
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
select uuid()
</selectKey>
INSERT INTO user VALUES (null, #{username},#{birthday},#{sex},#{address})
</insert>
#{} 和 ${} 的区别
#{}表示一个占位符号,通过#{}可以实现parameterType向占位符中设置值,自动进行java类型和jdbc类型转换
#{}可以有效防止sql注入。
#{}可以接收简单类型值或pojo属性值。
如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换
${}可以接收简单类型值或pojo属性值,
如果parameterType传输单个简单类型值,${}括号中只能是value
selectOne 和 selectList
- selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常
- selectList可以查询一条或多条记录
mybatis 解决 jdbc 编程的问题
- 在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库连接
- 将sql语句配置在mapper.xml文件中与java代码分离
- mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型
- mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型
与hibernate的区别
相同点:
hibernate与mybaits都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。
其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。
hibernate和mybaits都支持JDBC和JTA事务处理。
不同点:
hibernate是全自动,而mybatis是半自动
hibernate数据库移植性远大于mybatis
hibernate拥有完整的日志系统,mybatis则欠缺一些
mybatis相比hibernate需要关心很多细节
sql直接优化上,mybatis要比hibernate方便很多
缓存机制上,hibernate要比mybatis更好一些