1. Mybatis官网
下载地址
解压之后的内容:
Mybatis框架结构:
简要概述:
- SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句,此文件需要在SqlMapConfig.xml中加载。
- 通过mybatis环境等配置信息构造SqlSessionFactory(即会话工厂)。
- 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
- mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
- MappedStatement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个MappedStatement对象,sql的id即是MappedStatement的id。
- MappedStatement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过MappedStatement在执行sql前将输入的java对象映射至sql中,输入参数映射就是JDBC编程中对preparedStatement设置参数。
- MappedStatement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过MappedStatement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于JDBC编程中对结果的解析处理过程。
2. 导入数据库表
1). 使用Navicat工具,在root上右键选择新建数据库
2). 新建数据库->确定
3). 打开数据库mybatis->在mybatis/表处单击右键选择运行SQL文件...
4). 选择桌面的sql文件->点击开始
mybatis.sql文件内容
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `orders`
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '下单用户id',
`number` varchar(32) NOT NULL COMMENT '订单号',
`createtime` datetime NOT NULL COMMENT '创建订单时间',
`note` varchar(100) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES ('3', '1', '1000010', '2015-02-04 13:22:35', null);
INSERT INTO `orders` VALUES ('4', '1', '1000011', '2015-02-03 13:22:41', null);
INSERT INTO `orders` VALUES ('5', '10', '1000012', '2015-02-12 16:13:23', null);
-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '王五', null, '2', null);
INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '北京市');
INSERT INTO `user` VALUES ('16', '张小明', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('22', '陈小明', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('24', '张三丰', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('25', '陈小明', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('26', '王五', null, null, null);
5). 导入成功后,刷新表,数据如下:
3. 测试
1). 创建新的Java工程,并导入Mybatis使用的java包,注意要导入对应的数据库驱动包(这里导入的是mysql-connector-java-5.1.42-bin.jar)
2). 在工程目录下创建一个源码包config,并在config包下创建sqlmap包、log4j.properties和SqlMapConfig.xml文件。
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
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的核心配置文件,以上文件的配置内容为数据源、事务管理。
注意:等后面mybatis和Spring两个框架整合之后,environments的配置将被废除.
3). 创建一个po类--User
po类作为mybatis进行sql映射使用,po类通常与数据库表对应,User.java文件的内容如下:
public class User {
// id
private int id;
// 用户名
private String username;
// 性别
private String sex;
// 用户名
private Date birthday;
// 地址
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
+ address + "]";
}
}
4). 在classpath下的sqlmap目录下创建sql映射文件user.xml
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">
<mapper namespace="test">
</mapper>
- namespace:即命名空间,其用于隔离sql语句(即不同sql映射文件中的两个相同id的sql语句如何来区分)
5). 加载映射文件
mybatis框架需要加载映射文件,将user.xml添加在SqlMapConfig.xml中.
在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>
<!-- 添加的内容 -->
<mappers>
<!-- resource是基于classpath来查找的 -->
<mapper resource="sqlmap/user.xml"/>
</mappers>
</configuration>
6). 入门程序测试——根据id查询用户信息
I. 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">
<mapper namespace="test">
<!-- 根据id获取用户信息,
parameterType: 查询参数的数据类型,即定义输入到sql中的映射类型
resultType: 查询结果的数据类型,如果是pojo则该给出全路径
#{id}表示使用PreparedStatement设置占位符号并将输入变量id传到sql中,#{}作用就是占位符,相当于JDBC中的?
-->
<select id="getUserById" parameterType="int" resultType="com.mazaiting.po.User">
select * from user where id = #{id};
</select>
</mapper>
II. 编写MybatisTest类
public class MybatisTest {
@Test
public void testGetUserById() throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(inputStream);
// 4. 创建SqlSession对象
SqlSession sqlSession = factory.openSession();
// 5. 使用SqlSession对象执行查询,得到User对象
// 第一个参数: 执行查询的StatementId,即配置文件user.xml中的id, 第二参数传入id对应的值
User user = sqlSession.selectOne("getUserById", 10);
// 6. 打印结果
System.out.println(user);
// 7. 释放资源
sqlSession.close();
}
}
III. 执行测试代码, 打印结果:
IV. 优化代码
一般来讲工厂对象一般在实际开发是单例的,并不需要频繁地创建
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
factory = builder.build(inputStream);
}
@Test
public void testGetUserById() {
// 4. 创建SqlSession对象
SqlSession sqlSession = factory.openSession();
// 5. 使用SqlSession对象执行查询,得到User对象
// 第一个参数: 执行查询的StatementId,即配置文件user.xml中的id, 第二参数传入id对应的值
User user = sqlSession.selectOne("getUserById", 10);
// 6. 打印结果
System.out.println(user);
// 7. 释放资源
sqlSession.close();
}
}
7). 根据用户名称模糊查询用户信息列表
I. 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">
<mapper namespace="test">
<!-- 如果查询结果返回的是List集合,那么resultType只需要设置为List集合中的一个元素的数据类型 -->
<select id="getUserByName" parameterType="string" resultType="com.mazaiting.po.User">
select * from user where username like #{username}
</select>
</mapper>
II. 编写测试方法
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
factory = builder.build(inputStream);
}
@Test
public void testGetUserByName() {
SqlSession session = factory.openSession();
List<User> list = session.selectList("getUserByName", "%张%");
for (User user : list) {
System.out.println(user.toString());
}
session.close();
}
}
III. 执行测试方法,打印结果:
IV. 另一个中不建议使用的占位符方式
<?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">
<!-- 如果查询结果返回的是List集合,那么resultType只需要设置为List集合中的一个元素的数据类型 -->
<select id="getUserByName1" parameterType="string" resultType="com.mazaiting.po.User">
select * from user where username like '%${value}%'
</select>
</mapper>
测试代码:
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
factory = builder.build(inputStream);
}
@Test
public void testGetUserByName1() {
SqlSession session = factory.openSession();
List<User> list = session.selectList("getUserByName1", "张");
for (User user : list) {
System.out.println(user.toString());
}
session.close();
}
}
不推荐使用:原因容易引起SQL注入。
总结
---{}和${}
1). #{}
:表示一个占位符号,可以很好地去避免sql注入。其原理是将占位符位置的整个参数和sql语句两部分提交给数据库,数据库去执行sql语句,去表中匹配所有的记录是否和整个参数是否一致。#{}
要获取输入参数的值:
- 如果输入参数是简单数据类型,则
#{}
中可以写value或其它名称。 - 如果输入参数是pojo对象类型,则
#{}
可通过OGNL方式去获取,表达式就是属性.属性.属性....
方式。
2). ${}
表示一个sql拼接符号,其原理是在向数据库发出sql之前去拼接好sql再提交给数据库执行。${}
要获取输入参数的值:
- 如果输入参数是简单数据类型,则
${}
中只能写value。 - 如果输入参数是pojo对象类型,则
${}
可通过OGNL方式去获取,表达式就是属性.属性.属性....
方式。
一般情况下建议使用#{}
,特殊情况下必须要用${}
,比如:
1>. 动态拼接sql中动态组成排序字段,要通过${}
将排序字段传入sql中。
2>. 动态拼接sql中动态组成表名,要通过${}
将表名传入sql中。
---parameterType和resultType
- parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。
- resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。
---selectOne()和selectList()方法
- selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常.
- selectList可以查询一条或多条记录。
4. 其他操作
1). 插入数据
I. 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">
<mapper namespace="test">
<!-- 插入数据 -->
<insert id="addUser" parameterType="com.mazaiting.po.User">
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
如果输入参数是pojo,那么#{}中的名称就是pojo类中的属性(用到了对象图导航的思想)
II. 编写测试代码
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
factory = builder.build(inputStream);
}
@Test
public void testAddUser() {
// 创建Session对象
SqlSession session = factory.openSession();
// 创建对象
User user = new User();
user.setUsername("mazaiting");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("科学院");
// 插入数据
session.insert("addUser", user);
// 关闭Session
session.close();
}
}
III. 执行测试代码,打印结果:
可以看出虽然执行了sql语句,但是事务并没有提交,而是回滚了。
IV. 因此,应将测试代码修改为
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
factory = builder.build(inputStream);
}
@Test
public void testAddUser() {
// 创建Session对象
SqlSession session = factory.openSession();
// 创建对象
User user = new User();
user.setUsername("mazaiting");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("科学院");
// 插入数据
session.insert("addUser", user);
// 提交事务
session.commit();
// 关闭Session
session.close();
}
}
V. 执行单元测试,打印结果:
2). 自增主键返回
- LAST_INSERT_ID():返回auto_increment自增列新记录id值。该函数是在当前事务下取到你最后生成的id值,而我们应知道查询操作是没有开启事务的,增删改操作是需要开启事务的。
I. 在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">
<mapper namespace="test">
<!-- 插入数据,返回主键 -->
<insert id="addUser" parameterType="com.mazaiting.po.User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
- keyProperty:返回的主键存储在pojo中的哪个属性(即其对应pojo的主键属性)。获取主键,实际上是将主键取出来之后封装到了pojo的主键属性当中。
- resultType:返回的主键是什么类型(即其对应pojo的主键的数据类型)。
- order:selectKey的执行顺序,是相对于insert语句来说的,由于mysql的自增原理,执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为AFTER。
II. 添加测试代码
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
factory = builder.build(inputStream);
}
@Test
public void testAddUser1() {
// 创建Session对象
SqlSession session = factory.openSession();
// 创建对象
User user = new User();
user.setUsername("mazaiting");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("科学院");
// 插入数据
session.insert("addUser1", user);
System.out.println("插入的id:" + user.getId());
// 提交事务
session.commit();
// 关闭Session
session.close();
}
}
III. 执行测试代码,打印结果:
3). 删除用户
I. 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">
<mapper namespace="test">
<!-- 删除数据 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
</mapper>
II. 测试代码
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
factory = builder.build(inputStream);
}
@Test
public void testDeleteUser() {
// 创建会话
SqlSession session = factory.openSession();
// 删除数据
session.delete("deleteUser", 29);
// 提交事务
session.commit();
// 关闭会话
session.close();
}
}
III. 打印结果:
4). 更新数据
I. 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">
<mapper namespace="test">
<!-- 修改用户信息 -->
<update id="updateUser" parameterType="com.mazaiting.po.User">
update user set username = #{username} where id = #{id}
</update>
</mapper>
II. 测试代码
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 创建SqlSessionFactory对象
factory = builder.build(inputStream);
}
public void testUpdateUser(){
// 创建会话
SqlSession session = factory.openSession();
User user = new User();
user.setId(10);
user.setUsername("张某某");
// 更新数据
session.update("updateUser", user);
// 提交事务
session.commit();
// 关闭会话
session.close();
}
}
III. 打印结果:
5. Mybatis与Hibernate不同
- MyBatis学习成本低,入门门槛低。MyBatis需要程序员自己写sql,对sql修改和优化就比较灵活。MyBatis是不完全的ORM框架,MyBatis需要程序员编写sql,但是MyBatis也存在映射(输入映射、输出映射)适用场景:需求变化较快的项目开发,比如互联网项目、电商。
- Hibernate学习成本高,入门门槛高,Hibernate是ORM框架,不需要程序员编写sql,自动根据对象映射生成sql。适用场景:需求固定的中小型项目,如OA系统、ERP系统。