MyBatis之工作原理,简单实体的增加、修改、删除、查询
一、MyBatis之工作原理
MyBatis是一个半自动映射框架。所谓半自动,是相对Hibernate全表映射而言的,MyBatis需要手动匹配提供POJO、SQL和映射关系。
我们知道,JDBC有四个核心对象:
(1)DriverManager,用于注册数据库连接
(2)Connection,与数据库连接对象
(3)Statement/PrepareStatement,操作数据库SQL语句的对象
(4)ResultSet,结果集或一张虚拟表
而MyBatis也有四大核心对象:
(1)SqlSession对象,该对象中包含了执行SQL语句的所有方法。类似于JDBC里面的Connection。
(2)Executor接口,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。类似于JDBC里面的Statement/PrepareStatement。
(3)MappedStatement对象,该对象是对映射SQL的封装,用于存储要映射的SQL语句的id、参数等信息。
(4)ResultHandler对象,用于对返回的结果进行处理,最终得到自己想要的数据格式或类型。可以自定义返回类型。
MyBatis的工作原理如下图所示:
上面中流程就是MyBatis内部核心流程,每一步流程的详细说明如下文所述:
(1)读取MyBatis的配置文件。mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接信息。
(2)加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。
(3)构造会话工厂。通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory。
(4)创建会话对象。由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法。
(5)Executor执行器。MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。
(6)MappedStatement对象。在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息。
(7)输入参数映射。输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对preparedStatement对象设置参数的过程。
(8)输出结果映射。输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程。
二、简单实体的增加、修改、删除、查询
1、环境
mybatis-3.2版本,jdk1.8版本,Oracle数据库
2、准备工作
2.1 下载mybatis-3.2,需要引用其中的若干包,包括数据库JDBC驱动包
mybatis-3.2.0.jar lib/asm-3.3.1.jar lib/cglib-2.2.2.jar lib/commons-logging-1.1.1.jar lib/javassist-3.17.1-GA.jar lib/log4j-1.2.17.jar lib/slf4j-api-1.7.2.jar lib/slf4j-log4j12-1.7.2.jar
ojdbc6.jar
2.2 项目的目录结构
com.clzhang.mybatis.mapper MemberUserMapper.java MyBatis的mapper处理类(非必须) com.clzhang.mybatis.entity MemberUserBean.java MyBatis的entity类 com.clzhang.mybatis MyBatisTest1.java/MyBatisTest2.java 测试类
resources\config mybatis-config.xml MyBatis的配置文件
resources\com\clzhang\mybatis\mapper MemberUserMapper.xml MyBatis的mapper配置文件
2.3 假定数据库已经创建,表结构也已经创建,并且有测试数据
CREATE TABLE MEMBER_USER ( ID NUMBER NOT NULL PRIMARY KEY, NAME VARCHAR2(30), PERSONMOBILE VARCHAR2(20), ADDRESS VARCHAR2(255), AGE NUMBER); CREATE SEQUENCE SEQ_MEMBER_USER;
3、具体步骤
3.1 创建entity类
package com.clzhang.mybatis.entity; public class MemberUserBean { private int id; private String name; private String personMobile; private String address; private int 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 getPersonMobile() { return personMobile; } public void setPersonMobile(String personMobile) { this.personMobile = personMobile; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "MemberUser [id=" + id + ", name=" + name + ", personMobile=" + personMobile + ", address=" + address + ", age=" + age + "]"; } }
3.2 创建Mapper接口(非必须)
package com.clzhang.mybatis.mapper; import java.util.*; import com.clzhang.mybatis.entity.MemberUserBean; public interface MemberUserMapper { public void insertUser(MemberUserBean user); public void updateUser(MemberUserBean user); public void deleteUser(int id); public MemberUserBean getUserById(int id); public List getUsersByAge(int startAge, int endAge); }
3.3 创建mybatis-config.xml的配置文件,位置于resources/config目录
<?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> <settings> <setting name="cacheEnabled" value="false" /> <setting name="useGeneratedKeys" value="true" /> <setting name="defaultExecutorType" value="REUSE" /> </settings> <typeAliases> <typeAlias alias="MemberUser" type="com.clzhang.mybatis.entity.MemberUserBean"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> <property name="username" value="mytest"/> <property name="password" value="test001"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/clzhang/mybatis/mapper/MemberUserMapper.xml" /> </mappers> </configuration>
3.4 创建MemberUserMapper.xml配置文件,位置于:resources\com\clzhang\mybatis\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"> <mapper namespace="com.clzhang.mybatis.mapper.MemberUserMapper"> <!-- 默认情况下是没有开启缓存的,下条代码是开启二级缓存的,作用如下: 1.•映射语句文件中的所有 select 语句将会被缓存。 2.•映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。 3.•缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。 ...... --> <cache /> <!--以单个对象方式返回--> <select id="getUserById" resultType="MemberUser" parameterType="int"> select ID, NAME, PERSONMOBILE, ADDRESS, AGE FROM MEMBER_USER WHERE ID = #{id} </select> <resultMap type="MemberUser" id="userAgeMap"> <id property="id" column="id"/> <!--有需要做数据库到实体类名称转换的,可以写在这里--> <!-- <result property="objname" column="dbname"/> --> </resultMap> <!--以List方式返回多个结果--> <!--参数名称目前不可以自行指定(无法与Mapper中保持一致),待查--> <select id="getUsersByAge" resultMap="userAgeMap" parameterType="int"> <![CDATA[ select ID, NAME, PERSONMOBILE, ADDRESS, AGE FROM MEMBER_USER WHERE AGE > #{param1} AND AGE < #{param2} ]]> </select> <!--Oracle的实现自增长主键的方式--> <insert id="insertUser" parameterType="MemberUser"> <selectKey keyProperty="id" resultType="int" order="BEFORE"> select SEQ_MEMBER_USER.nextval from DUAL </selectKey> INSERT INTO MEMBER_USER (ID, NAME, PERSONMOBILE, ADDRESS, AGE) VALUES(#{id}, #{name}, #{personMobile}, #{address}, #{age}) </insert> <update id="updateUser" parameterType="MemberUser"> update MEMBER_USER set NAME = #{name}, PERSONMOBILE = #{personMobile}, ADDRESS = #{address}, AGE = #{age} where id = #{id} </update> <delete id="deleteUser" parameterType="int"> delete from MEMBER_USER where ID = #{id} </delete> </mapper>
3.5 创建测试类一,调用SqlSession实现CRUD
package com.clzhang.mybatis; import java.io.IOException; import java.io.Reader; import java.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 org.junit.Test; import com.clzhang.mybatis.entity.MemberUserBean; public class MyBatisTest1 { private static final String MYBATIS_CONFIG_FILENAME = "config/mybatis-config.xml"; private static SqlSessionFactory sqlSessionFactory; static { Reader reader = null; try { reader = Resources.getResourceAsReader(MYBATIS_CONFIG_FILENAME); } catch (IOException e) { System.out.println(e.getMessage()); } // 一旦你创建了 SqlSessionFactory后,SqlSessionFactoryBuilder这个类就不需要存在了。 sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } /** * SqlSessionFactory 应该在你的应用执行期间都存在。没有理由来处理或重新创建它。 * * @return */ public static SqlSessionFactory getSqlSessionFactory() { return sqlSessionFactory; } // @Test public void testInert() { // SqlSession 的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。 SqlSession sqlSession = getSqlSessionFactory().openSession(); try { MemberUserBean memberUser = new MemberUserBean(); memberUser.setName("李勇"); memberUser.setPersonMobile("998877"); memberUser.setAddress("江苏某地方"); memberUser.setAge(38); int rows = sqlSession.insert("com.clzhang.mybatis.mapper.MemberUserMapper.insertUser", memberUser); if (rows > 0) { System.out.println("您成功插入" + rows + "条数据!"); } else { System.out.println("执行插入操作失败!!!"); } sqlSession.commit(); // 查看新加的对象主键 System.out.println("新加对象的id:" + memberUser.getId()); } finally { sqlSession.close(); } } // @Test public void testUpdate() { SqlSession sqlSession = getSqlSessionFactory().openSession(); try { MemberUserBean memberUser = new MemberUserBean(); memberUser.setId(5); memberUser.setName("赵五"); memberUser.setPersonMobile("12345"); memberUser.setAddress("天津上地某公司"); memberUser.setAge(29); int rows = sqlSession.update("com.clzhang.mybatis.mapper.MemberUserMapper.updateUser", memberUser); if (rows > 0) { System.out.println("您成功更新" + rows + "条数据!"); } else { System.out.println("执行更新操作失败!!!"); } sqlSession.commit(); } finally { sqlSession.close(); } } // @Test public void testDelete() { SqlSession sqlSession = getSqlSessionFactory().openSession(); try { int rows = sqlSession.delete("com.clzhang.mybatis.mapper.MemberUserMapper.deleteUser", 5); if (rows > 0) { System.out.println("您成功删除" + rows + "条数据!"); } else { System.out.println("执行删除操作失败!!!"); } sqlSession.commit(); } finally { sqlSession.close(); } } // @Test public void getUser() { SqlSession sqlSession = getSqlSessionFactory().openSession(); try { MemberUserBean memberUser = sqlSession.selectOne("com.clzhang.mybatis.mapper.MemberUserMapper.getUserById", 1); System.out.println(memberUser.toString()); } finally { sqlSession.close(); } } // @Test public void getUserByAge() { SqlSession sqlSession = getSqlSessionFactory().openSession(); try { Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("param1", 20); paramMap.put("param2", 30); List<MemberUserBean> memberUsers = sqlSession.selectList("com.clzhang.mybatis.mapper.MemberUserMapper.getUsersByAge", paramMap); for (MemberUserBean memberUser : memberUsers) { System.out.println(memberUser); } } finally { sqlSession.close(); } } }
3.6 创建测试类二,调用Mapper接口实现CRUD
package com.clzhang.mybatis; import java.io.IOException; import java.io.Reader; import java.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 org.junit.Test; import com.clzhang.mybatis.mapper.MemberUserMapper; import com.clzhang.mybatis.entity.MemberUserBean; public class MyBatisTest2 { private static final String MYBATIS_CONFIG_FILENAME = "config/mybatis-config.xml"; private static SqlSessionFactory sqlSessionFactory; static { Reader reader = null; try { reader = Resources.getResourceAsReader(MYBATIS_CONFIG_FILENAME); } catch (IOException e) { System.out.println(e.getMessage()); } // 一旦你创建了 SqlSessionFactory后,SqlSessionFactoryBuilder这个类就不需要存在了。 sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } /** * SqlSessionFactory 应该在你的应用执行期间都存在。没有理由来处理或重新创建它。 * * @return */ public static SqlSessionFactory getSqlSessionFactory() { return sqlSessionFactory; } // @Test public void testInert() { // SqlSession 的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。 SqlSession sqlSession = getSqlSessionFactory().openSession(); try { MemberUserBean memberUser = new MemberUserBean(); memberUser.setName("李勇"); memberUser.setPersonMobile("998877"); memberUser.setAddress("江苏某地方"); memberUser.setAge(38); MemberUserMapper mapper = sqlSession .getMapper(MemberUserMapper.class); mapper.insertUser(memberUser); sqlSession.commit(); // 查看新加的对象主键 System.out.println("新加对象的id:" + memberUser.getId()); } finally { sqlSession.close(); } } // @Test public void testUpdate() { SqlSession sqlSession = getSqlSessionFactory().openSession(); try { MemberUserBean memberUser = new MemberUserBean(); memberUser.setId(6); memberUser.setName("赵五"); memberUser.setPersonMobile("12345"); memberUser.setAddress("天津上地某公司"); memberUser.setAge(29); MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class); mapper.updateUser(memberUser); sqlSession.commit(); } finally { sqlSession.close(); } } // @Test public void testDelete() { SqlSession sqlSession = getSqlSessionFactory().openSession(); try { MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class); mapper.deleteUser(6); sqlSession.commit(); } finally { sqlSession.close(); } } // @Test public void getUser() { SqlSession sqlSession = getSqlSessionFactory().openSession(); try { MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class); MemberUserBean memberUser = mapper.getUserById(1); System.out.println(memberUser.toString()); } finally { sqlSession.close(); } } @Test public void getUserByAge() { SqlSession sqlSession = getSqlSessionFactory().openSession(); try { MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class); List<MemberUserBean> myList = mapper.getUsersByAge(20, 40); for (MemberUserBean entry : myList) { int key = entry.getId(); String value = entry.getAddress(); System.out.println(key + ":" + value); } } finally { sqlSession.close(); } } }
4、单独测试各个模块
解除注释JUnit各单元,然后键盘输入:alt+shift+X,T,分别进行测试。
本文参考:http://www.mybatis.cn/archives/706.html