本文共 12882 字,大约阅读时间需要 42 分钟。
https://mybatis.org/mybatis-3/zh/index.html
注:底层如何获取标签值,请自行研究(剧透:for循环遍历XML获取标签中的值,然后放入Map)!~
mybatis底层自定义了Executor执行器接口来具体操作数据库,Executor接口有两个实现,一个是基本执行器(默认),一个缓存执行器,SqlSession底层是通过executor接口操作数据库
他是mybatis一个底层封装对象,包装了mybatis配置信息及XXXMapper.xml映射文件等。XXXMapper.xml文件中一个个select/insert/update/delete标签对应一个Mapped Statement对象。
原始JDBC和mybatis操作数据库数据,与上面架构图流程相对应。
public class JDBCTest { public static void main(String[] args) { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { // 加载数据库驱动 Class.forName("com.mysql.jdbc.Driver"); // 通过驱动管理类获取数据库链接connection = DriverManager connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root" ); // 定义sql语句 ?表示占位符 String sql = "select * from user where username = ?"; // 获取预处理 statement preparedStatement = connection.prepareStatement(sql); // 设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的 preparedStatement.setString(1, "王五"); // 向数据库发出 sql 执行查询,查询出结果集 resultSet = preparedStatement.executeQuery(); // 遍历查询结果集 while (resultSet.next()) { System.out.println( resultSet.getString("id") + " " + resultSet.getString("username") ); } } catch (Exception e) { e.printStackTrace(); } finally { // 释放资源 if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }}
pom.xml
4.0.0 com.cyb mybatis war 0.0.1-SNAPSHOT mybatis Maven Webapp http://maven.apache.org org.mybatis mybatis 3.4.6 mysql mysql-connector-java 8.0.20 junit junit 4.12 mybatis
db.properties
db.driver=com.mysql.jdbc.Driverdb.url=jdbc:mysql://127.0.0.1:3306/cybdb.username=rootdb.password=root
package com.cyb.mybatis.demo;import java.util.Date;public class User { private int id; private String username; private Date birthday; private int sex; 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 Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", birthday=" + birthday + ", sex=" + sex + ", address=" + address + "]"; }}
package com.cyb.mybatis.demo;import java.io.InputStream;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.Before;import org.junit.Test;public class MybatisDemo { private SqlSessionFactory sqlSessionFactory; @Before public void init() throws Exception { //指定全局配置文件路径 String resource = "SqlMapConfig.xml"; //加载资源文件(包括全局文件和映射文件) InputStream inputStream = Resources.getResourceAsStream(resource); //使用构建者模式创建SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testSelect() { //由SqlSessionFactory工厂去创建SqlSession(会话) SqlSession sqlSession = sqlSessionFactory.openSession(); //调用SqlSession接口,去实现数据库的CRUD User user = sqlSession.selectOne("test.queryUserById", 1); System.out.println(user); //释放资源 sqlSession.close(); }}
主键返回
select LAST_INSERT_ID() insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address});
添加selectKey标签实现主键返回。
* keyProperty:指定返回的主键,存储在pojo中的哪个属性
* order:selectKey标签中的sql的执行顺序,是相对与insert语句来说。由于mysql的自增原理,执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after。
* resultType:返回的主键对应的JAVA类型
* LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。
使用:只需要开发Mapper接口(Dao接口)和xxxMapper约束文件,不需要编写实现类。
开发规范:
4.0.0 com.cyb mybatis war 0.0.1-SNAPSHOT mybatis Maven Webapp http://maven.apache.org org.mybatis mybatis 3.4.6 mysql mysql-connector-java 8.0.20 junit junit 4.12 mybatis
db.driver=com.mysql.jdbc.Driverdb.url=jdbc:mysql://127.0.0.1:3306/cybdb.username=rootdb.password=root
package com.cyb.mybatis.demo;import java.util.Date;public class User { private int id; private String username; private Date birthday; private int sex; 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 Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", birthday=" + birthday + ", sex=" + sex + ", address=" + address + "]"; }}
package com.cyb.mybatis.mapper;import com.cyb.mybatis.demo.User;public interface UserMapper { /** * 根据用户id查询用户信息 * @param id 内码 * @return * @throws Exception */ public User queryUserById(int id) throws Exception;}
package com.cyb.mybatis.demo;import java.io.InputStream;import java.util.Date;import java.util.List;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.Before;import org.junit.Test;import com.cyb.mybatis.mapper.UserMapper;public class MybatisDemo { private SqlSessionFactory sqlSessionFactory; @Before public void init() throws Exception { // 指定全局配置文件路径 String resource = "SqlMapConfig.xml"; // 加载资源文件(包括全局文件和映射文件) InputStream inputStream = Resources.getResourceAsStream(resource); // 使用构建者模式创建SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testSelect() throws Exception { // 由SqlSessionFactory工厂去创建SqlSession(会话) SqlSession sqlSession = sqlSessionFactory.openSession(); // 调用SqlSession接口,去实现数据库的CRUD UserMapper userMapper=sqlSession.getMapper(UserMapper.class); User user = userMapper.queryUserById(1); System.out.println(user); // 释放资源 sqlSession.close(); }}
可以引入java属性文件中的配置信息
别名的作用:为了简化映射文件中parameterType和resultType中POJO类型的包名
注:可以写多个package,但是package和typeAlias不能一起用!!!
注:可以写多个typeAlias,但是package和typeAlias不能一起用!!!
注:一次加载一个映射文件,相当于资源路径
注册指定包下的所有mapper接口,来加载mapper映射文件。
注:mapper接口和mapper映射文件名称相同,且放到同一目录下
Collection标签:定义了一对多关联的结果映射。property="orders":关联查询的结果集存储在User对象的上哪个属性。ofType="orders":指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名。
下面我们具体的查看下是如何构建SqlSessionFactory对象
通过源码可以看出,最终会生成一个DefaultSqlSessionFactory实例,这个不是我们关注的重点,我们核心是关注如何初始化对象的。
build函数首先会构造一个XMLConfigBuilder对象,他是解析XML配置文件的。
这些XMLxxxBuilder都有一个共同的父类->BaseBuilder。这个父类维护了全局的Configuration对象,mybatis的配置文件解析后就以Configuration对象的形式存储。
底层代码量较多,录制的gif图片较大不能上传,分3段上传的,内容都是连续的;这里抛块砖,实际还是要自己打个断点,跟踪下底层源码,根据自身爱好,研究相应内容,准备工作:了解知识点:XPath(如,解析XML配置文件,)、设计模式(如:构建者模式,)、面向对象等等,要不然跟踪源码是件很痛苦的事儿~~~
注意:此处用到了遍历list节点,因为映射文件有很多的select、update、delete标签哦~
我们可以看到,SqlSessionFactory是一个接口,里面有很多重载方法
通过跟踪到DefaultSqlSessionFactory,我们可以看到,底层使用了重载,默认自动提交事务未false,从而解答了,我们使用默认无参构造函数时,对数据库进行:插入、修改、删除,需要手动提交事务
细心的小伙伴此时会问,问什么跟踪源码的时候,他不是有两个实现类吗,为什么要跟踪上面一个,不跟踪下面那个,是因为创建SqlSessionFactory的时候,默认返回的是DefaultSqlSessionFactory
我们跟踪下,是如何从Configuration全局配置文件中(从Map中获取),获取MapperStatement的;注:这个全局配置文件(configuration)是在初始化SqlSessionFactory时加载的
接下来我们跟踪下,是如何解析传递的参数的,分3种处理情况,分别为:集合、list、其他;注:参数类型与xxxMapper.xml的parameterType类型想对应,传什么类型,走什么情况
先走下面那个实现类,在走上面那个实现类
为什么先走下面那个实现类呢?看gif,先委托下面那个实现类
打个断点,调试下就知道了!!
转载地址:http://qdmkz.baihongyu.com/