架构分析
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。 MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索。MyBatis 可以使用简单的XML 或注解用于配置和原始映射,将接口和 Java 的 POJO( Plain Old Java Objects,普通的Java 对象)映射成数据库中的记录。
该图引用于51CTO
借助于该架构图我们可以发现,Mybatis的功能架构分为三层:
(1)API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
(2)数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
(3) 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
作为持久层框架,mybatis可以将程序中的大量sql语句剥离出来,配置在配置文件中,实现sql的灵活配置。可以将sql语句和代码分离,无需修改代码,在配置文件中修改配置文件即可到达修改sql的目的。
开发人员面对的是纯粹的java对象,和hibernate的orm思想一致。但对于具体的数据操作,hibernate会自动生成sql语句,而mybatis使用的时候,需要开发人员编写配置文件,将sql所需要的参数和返回的结果字段映射到具体的pojo。
maven依赖
为了方便,构建的是maven项目,需要的依赖分别有:
- junit (java单元测试依赖)
- mybatis(mybatis依赖)
- mysql (mysql数据库依赖)
- log4j (日志信息依赖)
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.1</version> </dependency> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>
建立数据库
为了测试mybatis的功能,首先建立一个简单的数据库,比较简单,数据库字段含义不再赘述。
create database mybatis;
use mybatis;
CREATE TABLE `tb_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(18) DEFAULT NULL, `sex` char(2) DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) )
建立pojo对象
在这里建立了一个非常简单的pojo类,用于测试mybatis的功能。
/** * fayuan.com Inc. * Copyright (c) 2017-2018 All Rights Reserved. */ package com.fayuan.domain; /** * 用户类 * * @author fayuan.fzw * @version $Id: User.java, v 0.1 2018年02月18日 上午11:05 fayuan.fzw Exp $ */ public class User { /** id */ private int id; /** 姓名 */ private String name; /** 性别 */ private String sex; /** 年龄 */ private int age; public User(String name, String sex, int age) { this.name = name; this.sex = sex; this.age = age; } public int getId() { return id; } public void setId(int 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 int getAge() { return age; } public void setAge(int age) { this.age = age; } }
这个类其实就是一个普通的javaBean,mybatis使用pojo类作为持久化类,这也是mybatis低侵入设计的关键。mybatis不需要持久化类继承任何父类,或者实现接口,可以保证代码的无侵入无污染。
pojo和数据库表字段映射
为了实现pojo和数据表中字段的映射,需要通过配置文件来配置具体的映射。
<?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="com.fayuan.mapper.UserMapper"> <!-- id="save"是唯一的标示符 parameterType属性指明插入时使用的参数类型 useGeneratedKeys="true"表示使用数据库的自动增长策略 --> <insert id="save" parameterType="com.fayuan.domain.User" useGeneratedKeys="true"> insert into tb_user (name,sex,age) VALUES (#{name},#{sex},#{age}) </insert> <!-- select操作 parameterType="int"表示该查询语句需要一个int类型的参数 resultType="user"表示返回的是一个user对象 --> <select id="select" parameterType="int" resultType="User"> select * from tb_user where id=#{id} </select> <!-- update操作 parameterType="user"表示该更新语句需要一个user对象作为参数--> <update id="update" parameterType="User"> update tb_user set name= #{name},sex= #{sex},age=#{age} where id= #{id} </update> <!-- delete操作 parameterType="int"表示该查询语句需要一个int类型的参数--> <delete id="delete" parameterType="int"> delete from tb_user where id=#{id} </delete> </mapper>
在这里一次性添加了增、删、查、改的映射关系,为了实现每一部分的功能,对于每一部分单独写一个测试类。
插入
/** * Alipay.com Inc. * Copyright (c) 2004-2018 All Rights Reserved. */ package com.fayuan.test; import java.io.InputStream; import com.fayuan.domain.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; /** * 测试插入功能 * * @author fayuan.fzw * @version $Id: InsertTest.java, v 0.1 2018年02月19日 下午4:02 fayuan.fzw Exp $ */ public class InsertTest { public static void main(String[] args) throws Exception { //读取mybatis-config.xml文件 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); //初始化mybatis,创建SqlSessionFactory类的实例 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //创建Session实例 SqlSession sqlSession = sqlSessionFactory.openSession(); //创建User对象 User user = new User ("fayuan","男",24); //插入数据 sqlSession.insert("com.fayuan.mapper.UserMapper.save", user); //提交事务 sqlSession.commit(); //关闭session sqlSession.close(); } }
打印出来的日志:
DEBUG [main] - ==> Preparing: insert into tb_user (name,sex,age) VALUES (?,?,?) DEBUG [main] - ==> Parameters: fayuan(String), 男(String), 24(Integer) DEBUG [main] - <== Updates: 1
查找
/** * fayuan.com Inc. * Copyright (c) 2017-2018 All Rights Reserved. */ package com.fayuan.test; import com.fayuan.domain.User; import com.fayuan.factory.SqlSessionFactoryClass; import org.apache.ibatis.session.SqlSession; /** * 测试查找功能 * * @author fayuan.fzw * @version $Id: SelectTest.java, v 0.1 2018年02月24日 下午11:19 fayuan.fzw Exp $ */ public class SelectTest { public static void main(String[] args) { //获取Session实例 SqlSession sqlSession = SqlSessionFactoryClass.getSqlSession(); // 创建User对象 User user = sqlSession.selectOne("com.fayuan.mapper.UserMapper.select", 1); System.out.println("name = " + user.getName() + ", sex = " + user.getSex() +", age = " + user.getAge()); //提交事务 sqlSession.commit(); //关闭Session sqlSession.close(); } }
打印出来的日志:
DEBUG [main] - ==> Preparing: select * from tb_user where id=? DEBUG [main] - ==> Parameters: 1(Integer) DEBUG [main] - <== Total: 1
修改
/** * fayuan.com Inc. * Copyright (c) 2017-2018 All Rights Reserved. */ package com.fayuan.test; import com.fayuan.domain.User; import com.fayuan.factory.SqlSessionFactoryClass; import org.apache.ibatis.session.SqlSession; /** * 测试修改功能 * @author fayuan.fzw * @version $Id: UpdateTest.java, v 0.1 2018年02月24日 下午11:03 fayuan.fzw Exp $ */ public class UpdateTest { public static void main(String[] args) { //获取Session实例 SqlSession sqlSession = SqlSessionFactoryClass.getSqlSession(); // 根据id查询User对象 User user = sqlSession.selectOne("com.fayuan.mapper.UserMapper.select",1); // 修改User对象的属性值 user.setName("tom"); user.setAge(25); // 修改User对象 sqlSession.update("update", user); // 提交事务 sqlSession.commit(); // 关闭Session sqlSession.close(); } }
打印出来的日志:
DEBUG [main] - ==> Preparing: select * from tb_user where id=? DEBUG [main] - ==> Parameters: 1(Integer) DEBUG [main] - <== Total: 1 DEBUG [main] - ==> Preparing: update tb_user set name= ?,sex= ?,age=? where id= ? DEBUG [main] - ==> Parameters: tom(String), ?(String), 25(Integer), 1(Integer) DEBUG [main] - <== Updates: 1
删除
/** * fayuan.com Inc. * Copyright (c) 2017-2018 All Rights Reserved. */ package com.fayuan.test; import com.fayuan.factory.SqlSessionFactoryClass; import org.apache.ibatis.session.SqlSession; /** * 测试删除功能 * * @author fayuan.fzw * @version $Id: DeleteTest.java, v 0.1 2018年02月24日 下午11:55 fayuan.fzw Exp $ */ public class DeleteTest { public static void main(String[] args) throws Exception { // 获得Session实例 SqlSession session = SqlSessionFactoryClass.getSqlSession(); // 删除id为1的User对象 session.delete("com.fayuan.mapper.UserMapper.delete", 1); // 提交事务 session.commit(); // 关闭Session session.close(); } }
打印出来的日志:
DEBUG [main] - ==> Preparing: delete from tb_user where id=? DEBUG [main] - ==> Parameters: 1(Integer) DEBUG [main] - <== Updates: 1
问题总结:
- 配置文件位置声明
- pojo需要加上无参构造,否则在内部的反射机制是无法获得pojo对象的
- 使用log4j观察执行状况
- aliases的使用
- 其他配置(pool、别名......)