1. MyBatis框架概述
mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
mybatis 通过xml 或注解的方式将要执行的各种statement 配置起来,并通过java 对象和statement 中sql的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql并将结果映射为 java 对象并返回。
采用 ORM 思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与 jdbc api打交道,就可以完成对数据库的持久化操作。
2. MyBatis入门案例
2.1 需求
使用MyBatis查询所有的用户, 封装到List集合
2.2 分析步骤
- 创建maven项目(jar)
- 创建pojo
- 创建dao接口
- 创建mybatis的核心配置文件SqlMapConfig.xml
- 创建dao接口的映射配置文件
- 引入log4j日志打印配置文件
- 编写测试代码
2.3 实现
2.3.1 准备工作
- 数据库
CREATE DATABASE mybatis;
USE mybatis;
CREATE TABLE user(
uid int PRIMARY KEY auto_increment,
username varchar(40),
sex varchar(10),
birthday date,
address varchar(40)
);
INSERT INTO `user` VALUES (null, 'zs', '男', '2018-08-08', '北京');
INSERT INTO `user` VALUES (null, 'ls', '女', '2018-08-30', '武汉');
INSERT INTO `user` VALUES (null, 'ww', '男', '2018-08-08', '北京');
- 创建maven项目
- 设置pom.xml配置文件, 引入依赖
<dependencies>
<!--junit的依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--引入lombok的依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
<!--mybatis的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!--引入日志打印依赖-->
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.6</version>
</dependency>
<!--log end-->
</dependencies>
- 引入日志打印log4j.poperties配置文件和jdbc.properties配置文件
4.1 log4j.poperties
-%m%nlog4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#[%-5p] %t %l %d %rms:%m%n
#%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p [%t] {%c}-%m%n
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %t %l %d %rms:%m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:\\idea_project\\itheima_mm_backend.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p [%t] {%c}
4.2 jdbc.properties
jdbc.username=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8
jdbc.driver=com.mysql.jdbc.Driver
2.3.2 核心配置文件的配置
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>
<!--1. 利用poperties标签引入外部jdbc配置信息-->
<properties resource="jdbc.properties"/>
<!--2. 通过typeAliases标签进行pojo对象的别名设置-->
<typeAliases>
<!--
每个typeAlias子标签就设置一个pojo的别名
type属性: 表示pojo对象的全限定名
alias属性: 表示要设置的别名
-->
<!--<typeAlias type="com.itheima.pojo.User" alias="User"/>-->
<!--
使用package子标签对pojo对象包扫描批量设置别名,
每个pojo类的类名就是别名(不区分大小写)
-->
<package name="com.itheima.pojo"/>
</typeAliases>
<!--
3. 配置连接数据库的环境, 每一个environments标签就是
一个数据库环境; 可以配置多个环境 default: 表示指定
使用哪个环境
-->
<environments default="dev">
<!--开发环境-->
<environment id="dev">
<!--配置事务, mybatis事务用的是JDBC-->
<transactionManager type="JDBC"/>
<!--
dataSource标签数据源:
1. UNPOOLED: 表示不使用mybatis自带的连
接池
2. POOLED: 表示使用mybatis内置的连接池
3. JNDI: 使用JNDI环境里的连接池
数据源里面要使用property子标签配置数据源的环境
-->
<!--
引入外部jdbc的配置信息, 用${key值}引入相应
的值
-->
<dataSource type="POOLED">
<!--数据库用户名-->
<property name="username" value="${jdbc.username}"/>
<!--数据库密码-->
<property name="password" value="${jdbc.password}"/>
<!--数据库地址-->
<property name="url" value="${jdbc.url}"/>
<property name="driver" value="${jdbc.driver}"/>
</dataSource>
</environment>
<!--测试环境-->
<environment id="test">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
<!--生产环境-->
<environment id="product">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<!--4. 加载映射配置文件-->
<mappers>
<!--每个mapper标签表示加载一个映射配置文件-->
<!--<mapper resource="com/itheima/dao/UserDao.xml"/>-->
<!--
可以使用package子标签进行包扫描, 批量加载映射配置文件
-->
<package name="com.itheima.dao"/>
</mappers>
</configuration>
注意事项
- 核心配置文件直接存储在resources目录下
- 一定要引入约束文件
- 在进行设置时一定要注意标签的顺序, 否则会报错(ctrl+鼠标左键点击根标签即可看到约束文件中标签的顺序, 如下图)
2.3.3 映射文件的配置
UserDao.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属性, 该属性就是对应
的dao接口的全限定名
-->
<mapper namespace="com.itheima.dao.UserDao">
<!--
每一个子标签就对应dao接口中的一个方法
dao接口中:
添加方法对应: insert标签
删除方法对应: delete标签
修改方法对应: update标签
查询方法对应: select标签
其中这些标签的属性:
id属性对应方法中的方法名
parameterType属性对应方法中的参数类型
resultType属性(只有查询select标签才有)就对应方法的返回值类型, 如果返回值类型是List
那么resultType就是List的泛型
-->
<!--查询所有-->
<select id="findAll" resultType="User">
<!--sql语句编写在标签体内-->
select * from t_user
</select>
<!--添加用户-->
<insert id="addUser" parameterType="User">
insert into t_user value (null, #{username}, #{sex}, #{birthday}, #{address})
<!--
<selectKey>子标签可以查询到自增长的id
keyColumn属性表示就是要查询的字段名
keyProperty属性表示将查询到的结果赋值给
哪个属性
resultType属性表示查询到属性的结果的类型
order属性表示在执行添加之前还是之后执行查
询自增长的id
标签体里写自增长的sql语句
-->
<selectKey keyColumn="uid" keyProperty="uid" resultType="int" order="AFTER">
<!--查询自增长id的sql语句-->
select last_insert_id()
</selectKey>
</insert>
<!--删除数据-->
<delete id="deleteUser" parameterType="int">
delete from t_user where uid = #{id}
</delete>
<!--查询一条数据-->
<select id="findById" parameterType="int" resultType="User">
select * from t_user where uid = #{id}
</select>
<!--修改数据-->
<update id="updateUser" parameterType="Map">
update t_user set username = #{username}, address = #{address} where uid = #{id}
</update>
<!--模糊查询-->
<select id="searchByUsername" parameterType="String" resultType="User">
<!--第一种方式-->
<!--select * from t_user where username like "%"#{username}"%"-->
<!--第二种方式-->
<!--select * from t_user where username like "%${username}%"-->
<!--第三种方式-->
select * from t_user where username like concat("%",#{username},"%")
</select>
</mapper>
注意事项
- 映射配置文件存储的路径在resources里面,要和对应的Dao接口的路径保持一致
- 映射配置文件的文件名必须和Dao接口名保持一致, 如图
- 一定要引入约束文件
- 引入参数中的数据, 如果是简单类型(String, 基本数据类型, 包装类), 则用#{任意字符}引入对应的值, 如果是pojo或者map类型的, 则需要用#{属性名}&#{key值}引入对应的值
#{}和${}的区别
- #{}不能写在引号里, ${}必须写在引号里面
- 如果是pojo或者map类型的参数, 则#{}和${}内都是写属性名或者key值
- 如果参数类型是简单类型, 则#{任意字符}和${任意字符}
- 如果用#{}引入参数的话是先使用?占位符, 然后再设置参数, 而使用${}引入参数时是直接拼接sql语句的
2.3.4 编写dao接口代码
UserDao接口
import com.itheima.pojo.User;
import java.util.List;
public interface UserDao {
/**
* 查询所有
* @return
*/
List<User> findAll();
/**
* 添加数据
* @param user
*/
void addUser(User user);
/**
* 删除数据
* @param id
*/
void deleteUser(Integer id);
/**
* 查询一条数据
* @param id
* @return
*/
User findById(Integer id);
/**
* 修改数据
* @param map
*/
void updateUser(User user);
/**
* 根据用户名模糊查询
* @return
*/
List<User> searchByUsername(String username);
}
2.3.5 封装工具类
SqlSessionFactoryUtils工具类
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class SqlSessionFactoryUtils {
private static InputStream is;
private static SqlSessionFactory sessionFactory;
static {
try {
//1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//2. 读取核心配置文件,转换成字节输入流
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//3. 创建SqlSessionFactory对象
sessionFactory = sqlSessionFactoryBuilder.build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession对象的方法
* @return
*/
public static SqlSession openSession(){
SqlSession sqlSession = null;
try {
//4. 创建SqlSession对象
sqlSession = sessionFactory.openSession();
is.close();
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
return sqlSession;
}
/**
* 提交事务并且关闭资源
* @param sqlSession
*/
public static void commitAndClose(SqlSession sqlSession){
sqlSession.commit();
sqlSession.close();
}
/**
* 回滚事务并且关闭资源
* @param sqlSession
*/
public static void rollbackAndClose(SqlSession sqlSession){
sqlSession.rollback();
sqlSession.close();
}
}
2.3.5 编写测试代码
import com.itheima.pojo.UserDao;
import com.itheima.pojo.User;
import com.itheima.utils.SqlSessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class TestMybatis {
private SqlSession sqlSession;
private UserDao userDao;
@Before
public void init() {
//1. 获取SqlSession对象
sqlSession = SqlSessionFactoryUtils.openSession();
//2. 获取LinkManDao的代理对象
userDao = sqlSession.getMapper(userDao.class);
}
@Test
public void test01() {
// 调用需要执行的方法
List<User> userList = userDao.findAll();
// 遍历打印
for (User user : userList) {
System.out.println(user);
}
}
@Test
public void test02() {
User user = new User(0, "zl", "男", new Date(), "北京");
userDao.addUser(user);
//添加成功后获取用户的自增id
int uid = user.getUid();
System.out.println(uid);
}
@Test
public void test03() {
userDao.deleteUser(6);
}
@Test
public void test04() {
User user = userDao.findById(2);
System.out.println(user);
}
@Test
public void test05() {
User user = new User();
user.setUserName("eason")
user.setAddress("hongkong")
userDao.updateUser(user);
}
@Test
public void test06() {
List<User> userList = userDao.searchByUsername("a");
for (User user : userList) {
System.out.println(user);
}
}
@After
public void destroy() {
//4. 提交事务关闭资源
SqlSessionFactoryUtils.commitAndClose(sqlSession);
}
}
3. 总结
- 核心配置文件直接存储在resources目录下, 映射配置文件也存储在resource目录下, 但路径需要和dao接口保持一致, 且配置文件名也和dao接口名保持一致
- 一定要引入约束文件
- 在配置核心配置文件时一定要注意标签的顺序, 否则会报错
- 如果没有在核心配置文件里进行pojo对象别名配置, 则在映射配置文件中的parameterType属性和resultType属性不能使用别名, 必须写权限定名(简单类型是内置配置的可以使用别名)
- 映射配置文件中mapper根标签包含namespace属性, 该属性就是对应的dao接口的全限定名, 其每个子标签就就对应dao接口中的一个方法;
- 映射配置文件子标签的属性:
id属性对应dao接口方法中的方法名
parameterType属性对应方法中的参数类型
resultType属性(只有查询select标签才有)就对应方法的返回值类型, 如果返回值类型是List,那么resultType就是List的泛型 - 引入参数中的数据, 如果是简单类型(String, 基本数据类型, 包装类), 则用#{任意字符}引入对应的值, 如果是pojo或者map类型的, 则需要用#{属性名}&#{key值}引入对应的值