运行环境
IDEA 2018 Maven Mysql 5.1.44 MyBatis 3.4.6
POM文件
代码语言:javascript复制 <dependencies>
<!--MyBatis JAR-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--MySQL JAR-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
</dependencies>
从JDBC谈起
代码语言:javascript复制首先我们先去准备以下数据,做一个User表,以下我们就根据user表来表述整个MyBatis的入门篇
跟着搭建环境的小伙伴可以直接复制这段sql执行
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`sex` varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`age` int(4) NULL DEFAULT NULL,
`phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
INSERT INTO `user` VALUES (1, '张三', '男', 18, '189----5487');
INSERT INTO `user` VALUES (2, '皇甫', '男', 24, '123----7536');
SET FOREIGN_KEY_CHECKS = 1;
对于传统的jdbc操作而言 我们通常都是怎么去连接数据库呢?先总结一下步骤
- 加载驱动
- 获取连接
- 准备sql
- 发送sql
- 填充参数
- 执行sql
- 执行查询的情况下获取结果集
- 关闭资源
代码语言:javascript复制那我们就根据传统JDBC去编写代码吧,进而引申出它的缺点以及为什么会有MyBatis的出现
package com.huangfu;
import java.sql.*;
/**
* 传统jdbc的测试方案
* 注意,再跟着练习的时候 请看清楚导包的名字 mysql jar包有重复包名,新手容易混淆
* @author 皇甫
*/
public class TestJdbc {
/**
* 测试查询语句
* @param args
*/
public static void main(String[] args) throws SQLException {
//数据库连接引用
Connection connection = null;
//sql执行器的引用
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//驱动加载
Class.forName("com.mysql.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://localhost:3306/testmybatis";
String userName = "root";
String password = "hr";
connection = DriverManager.getConnection(url, userName, password);
//准备sql
final String SQL = "select * from user where id=?";
//发送sql
preparedStatement = connection.prepareStatement(SQL);
//填充参数
preparedStatement.setInt(1, 1);
//执行sql
resultSet = preparedStatement.executeQuery();
//处理结果集
while (resultSet.next()){
System.out.println("id:" resultSet.getInt("id"));
System.out.println("name:" resultSet.getString("name"));
System.out.println("sex:" resultSet.getString("sex"));
System.out.println("age:" resultSet.getInt("age"));
System.out.println("phone:" resultSet.getString("phone"));
System.out.println("------------------------------------------");
}
}catch (Exception e){
e.printStackTrace();
} finally {
// 关闭连接,释放资源
if (resultSet != null) {
resultSet.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (connection != null) {
connection.close();
}
}
}
}
以上的jdbc缺点是什么呢,看一下下面图解分析?
思考一个问题,我们能不能将驱动加载和sql,从java代码中分离出来,写进配置文件里面呢,加载驱动和获取连接利用工厂模式获取呢?我们可以将
驱动加载
、获取连接
、发送sql
、执行sql
、关闭资源
;封装成一个JDBCUtil工具类;当然,这里有兴趣的同学可以自己封装一下,成功了别忘了告诉我这个好消息。
MyBatis
此时,我们上面所说的封装成工具类什么的,一个优秀的开源框架MyBatis全部都帮我们做到了,它将连接信息,以及SQL等全部都放入了配置文件,再配置文件中我们只需要关注SQL语句就OK了; MyBatis 是一款优秀的
持久层框架
,它支持定制化 SQL
、存储过程
以及高级映射
。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML
或注解
来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
MyBatis架构图
以上我们可以看出,其实MyBatis很简单
- MyBatisConfig.xml是一个全局的配置文件,一个项目内只能有一个。
- Mapper.xml是映射文件,可以有多个
- SqlSessionFactory见名知意,是一个SqlSession工厂,用于获取sqlSession;获取方式为
new SqlSessionFactoryBuilder.build(inputStream)
- SqlSession 用于操作SQL的CRUD(增删改查 )
- Executor执行器 执行sql
- Mapped Statement 在配置文件中配置
初识MyBatis
代码语言:javascript复制在Resources文件夹的根目录建立MyBatisConfig.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>
<!--配置默认使用那个环境变量 以id作为标志-->
<environments default="test">
<!--配置连接环境-->
<environment id="test">
<!--事务管理器使用JDBC-->
<transactionManager type="JDBC"/>
<!--数据源 连接池使用该POOLED-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/testmybatis"/>
<property name="username" value="root"/>
<property name="password" value="hr"/>
</dataSource>
</environment>
<!--配置多个连接环境,至于使用谁在environments指定-->
<environment id="development">
<!--事务管理器使用JDBC-->
<transactionManager type="JDBC"/>
<!--数据源 连接池使用该POOLED-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/testmybatis"/>
<property name="username" value="root"/>
<property name="password" value="hr"/>
</dataSource>
</environment>
</environments>
</configuration>
代码语言:javascript复制为了方便,建立映射数据库的实体类
package com.huangfu.entity;
/**
* 构建实体类
* @author 皇甫
*/
public class User {
private Integer id;
private String name;
private String sex;
private Integer age;
private String phone;
public User(Integer id, String name, String sex, Integer age, String phone) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
this.phone = phone;
}
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "User{"
"id=" id
", name='" name '''
", sex='" sex '''
", age=" age
", phone='" phone '''
'}';
}
}
代码语言:javascript复制在Resources文件夹建立Mapper文件夹,在创建Mapper文件
<?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 暂时可以随意写 保证命名空间唯一-->
<mapper namespace="myUser">
<!--ID保证唯一 resultType指定返回值类型-->
<select id="selectUser" resultType="com.huangfu.entity.User">
select * from user where id=#{id}
</select>
</mapper>
代码语言:javascript复制将Mapper文件注入到全局配置文件 ,此时查看完整的 mybatis-config.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>
<!--配置默认使用那个环境变量 以id作为标志-->
<environments default="test">
<!--配置连接环境-->
<environment id="test">
<!--事务管理器使用JDBC-->
<transactionManager type="JDBC"/>
<!--数据源 连接池使用该POOLED-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/testmybatis"/>
<property name="username" value="root"/>
<property name="password" value="hr"/>
</dataSource>
</environment>
<!--配置多个连接环境,至于使用谁在environments指定-->
<environment id="development">
<!--事务管理器使用JDBC-->
<transactionManager type="JDBC"/>
<!--数据源 连接池使用该POOLED-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/testmybatis"/>
<property name="username" value="root"/>
<property name="password" value="hr"/>
</dataSource>
</environment>
</environments>
<!--将Mapper文件在这里注册-->
<mappers>
<!--resource书写mapper所在文件的路径-->
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
代码语言:javascript复制准备工作完成,开始测试我们的使用是否正确
public class TestMyBatis {
/**
* 先将全局配置文件读入到内存
* 获取SqlSessionFactory
* 获取Session
*/
private InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
private SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
private SqlSession sqlSession = sqlSessionFactory.openSession();
public TestMyBatis() throws IOException {
}
/**
* 测试查询
* @throws IOException
*/
@Test
public void selectUser() throws IOException {
try{
//指定哪一个Mapper文件下的哪一个语句
//myUser对应Mapper文件中namespace的id名字 selectUser对应select id的名字
//第二个参数 1 代表 #{id} 即要给#{id} 传值为1
User user = sqlSession.selectOne("myUser.selectUser", 1);
System.out.println(user);
}catch (Exception e){
e.printStackTrace();
}finally {
if(sqlSession !=null){
sqlSession.close();
}
if(is != null){
is.close();
}
}
}
}
运行测试 User{id=1, name='张三', sex='男', age=18, phone='189----5487'}
查看何时执行的sql
代码语言:javascript复制导入日志jar包
<!--导入日志JAR-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
代码语言:javascript复制在Resources根目录创建文件 log4j.properties 并将下列日志文件复制进去
log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
再次运行查询,我们会看到控制台打印日志文件如下
目录结构
完整的演示一下MyBatis的增删改查
代码语言:javascript复制1.书写实体类
package com.huangfu.entity;
/**
* 构建实体类
* @author 皇甫
*/
public class User {
private Integer id;
private String name;
private String sex;
private Integer age;
private String phone;
public User(Integer id, String name, String sex, Integer age, String phone) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
this.phone = phone;
}
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "User{"
"id=" id
", name='" name '''
", sex='" sex '''
", age=" age
", phone='" phone '''
'}';
}
}
代码语言:javascript复制2.书写mybatis-config.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>
<!--配置默认使用那个环境变量 以id作为标志-->
<environments default="test">
<!--配置连接环境-->
<environment id="test">
<!--事务管理器使用JDBC-->
<transactionManager type="JDBC"/>
<!--数据源 连接池使用该POOLED-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/testmybatis"/>
<property name="username" value="root"/>
<property name="password" value="hr"/>
</dataSource>
</environment>
<!--配置多个连接环境,至于使用谁在environments指定-->
<environment id="development">
<!--事务管理器使用JDBC-->
<transactionManager type="JDBC"/>
<!--数据源 连接池使用该POOLED-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/testmybatis"/>
<property name="username" value="root"/>
<property name="password" value="hr"/>
</dataSource>
</environment>
</environments>
<!--将Mapper文件在这里注册-->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
代码语言:javascript复制3.书写Dao接口,映射到指定mapper
package com.complete;
import com.huangfu.entity.User;
/**
* 用户的增删改查
* @author 皇甫
*/
public interface UserDao {
/**
* 查询用户 根据ID
* @param id
* @return
*/
public User findOneUserById(Integer id);
/**
* 修改用户
* @param user
*/
public void updateUser(User user);
/**
* 增加一个用户
* @param user
*/
public void addUser(User user);
/**
* 删除一个用户
* @param id
*/
public void deleteUserById(Integer id);
}
代码语言:javascript复制书写Mapper
<?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 暂时可以随意写 保证命名空间唯一-->
<mapper namespace="myUser">
<!--ID保证唯一 resultType指定返回值类型-->
<!--查询-->
<select id="selectUser" resultType="com.huangfu.entity.User">
select * from user where id=#{id}
</select>
<!--插入-->
<insert id="insertUser" parameterType="com.huangfu.entity.User">
insert into
user(id,name,sex,age,phone)
values
(#{id},#{name},#{sex},#{age},#{phone})
</insert>
<!--修改-->
<update id="updateUser" parameterType="com.huangfu.entity.User">
update user set
name=#{name},sex=#{sex},age=#{age},phone=#{phone}
where
id=#{id}
</update>
<!--删除-->
<delete id="deleteUser">
delete from user where id=#{id}
</delete>
</mapper>
代码语言:javascript复制我为了简单,简易封装一个工具类,你们可以按照上面写的,不封装,一个一个写也行
package com.complete.util;
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;
/**
* MyBatis简易工具类
* @author 皇甫
*/
public class MyBatisUtil {
private static InputStream is = null;
private static SqlSessionFactory sqlSessionFactory = null;
static {
try {
is = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static SqlSession sqlSession = sqlSessionFactory.openSession();
public static SqlSession openSqlSession(){
return sqlSession;
}
public static void closeSqlSession(){
sqlSession.close();
}
}
代码语言:javascript复制书写Dao实现类
package com.complete.dao.impl;
import com.complete.dao.UserDao;
import com.complete.util.MyBatisUtil;
import com.huangfu.entity.User;
import org.apache.ibatis.session.SqlSession;
/**
*
* @author 皇甫
*/
public class UserDaoImpl implements UserDao {
private SqlSession sqlSession = null;
public UserDaoImpl() {
sqlSession = MyBatisUtil.openSqlSession();
}
public User findOneUserById(Integer id) {
User user = sqlSession.selectOne("myUser.selectUser", id);
MyBatisUtil.closeSqlSession();
return user;
}
public void updateUser(User user) {
try{
sqlSession.update("myUser.updateUser", user);
//事务控制
sqlSession.commit();
System.out.println("修改成功");
}catch (Exception e){
sqlSession.rollback();
e.printStackTrace();
}finally {
MyBatisUtil.closeSqlSession();
}
}
public void addUser(User user) {
try{
sqlSession.insert("myUser.insertUser",user);
//事务控制
sqlSession.commit();
System.out.println("插入成功");
}catch (Exception e){
sqlSession.rollback();
e.printStackTrace();
}finally {
MyBatisUtil.closeSqlSession();
}
}
public void deleteUserById(Integer id) {
try{
sqlSession.insert("myUser.deleteUser",id);
//事务控制
sqlSession.commit();
System.out.println("删除成功");
}catch (Exception e){
sqlSession.rollback();
e.printStackTrace();
}finally {
MyBatisUtil.closeSqlSession();
}
}
}
代码语言:javascript复制测试运行
package com.huangfu.testmybatis;
import com.complete.dao.UserDao;
import com.complete.dao.impl.UserDaoImpl;
import com.huangfu.entity.User;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
/**
* 测试MyBatis
* @author 皇甫
*/
public class MyBatisTest {
private UserDao ud = new UserDaoImpl();
@Test
public void testSelectUser(){
User user = ud.findOneUserById(1);
System.out.println(user);
}
@Test
public void testInsertUser(){
User user = new User(4, "赵六", "女", 20, "165----9574");
ud.addUser(user);
}
@Test
public void testUpdateUser(){
User user = new User(2, "皇甫", "男", 20, "165----9574");
ud.updateUser(user);
}
@Test
public void testDeleteUser(){
ud.deleteUserById(1);
}
}