mybtais 源码分析
一.最原始的使用jdbc连接mysql:
maven依赖只要一个:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency>
步骤:加载驱动(可以省略)—>获取连接对象—>创建预执行语句对象—>执行sql—>释放连接对象(口诀:贾琏欲执事)代码如下:
public class App { public static void main( String[] args ) { Connection connection=null; try { //获取连接对象 connection = DriverManager.getConnection("jdbc:mysql://192.168.50.117:23306/shop?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false", "shop", "shop"); String sql="update shop_order_attr set flg_type=? where cod_order_id=?"; //获取预执行语句 PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1,30); preparedStatement.setString(2,"666655555555"); connection.setAutoCommit(false); //执行sql boolean execute = preparedStatement.execute(); connection.commit(); if (execute){ System.out.println("成功"); } } catch (Exception e) { try { connection.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } }finally { if(connection!=null){ try { //释放连接对象 connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
接下来,我们看看mybatis是如何实现上面的功能的:
首先添加对应的maven 依赖
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency>
在resources文件夹下创建mybatis.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> <properties resource="mysql.properties" > </properties> <settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false"/> <setting name="autoMappingBehavior" value="PARTIAL"/> <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25"/> <setting name="defaultFetchSize" value="100"/> <setting name="safeRowBoundsEnabled" value="false"/> <setting name="mapUnderscoreToCamelCase" value="false"/> <setting name="localCacheScope" value="SESSION"/> <setting name="jdbcTypeForNull" value="OTHER"/> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> </settings> <typeAliases> <typeAlias type="com.yang.xiao.hui.entity.ShopOrderAttr" alias="shopOrderAttr"></typeAlias> <package name="com.yang.xiao.hui.entity"/> </typeAliases> <typeHandlers> <typeHandler handler="com.yang.xiao.hui.entity.ExampleTypeHandler"></typeHandler> </typeHandlers> <objectFactory type="com.yang.xiao.hui.entity.MyObjectFactory"></objectFactory> <reflectorFactory type="org.apache.ibatis.reflection.DefaultReflectorFactory"/> <plugins> <plugin interceptor="com.yang.xiao.hui.interceptor.MyInterceptor"></plugin> </plugins> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <databaseIdProvider type="DB_VENDOR" /> <mappers> <mapper resource="com/yang/xiao/hui/mapper/ShopOrderAttr.xml"/> </mappers> </configuration>
之后我们给张表shop_order_attr创建实体类 Mapper接口以及Mapper.xml文件:
之后在启动类加入如下代码:
public class MybatisApp { public static void main(String[] args) { String resource = "mybtais.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //读取mybatis.xml的内容获取sessionFactory的工厂 SqlSession sqlSession = sqlSessionFactory.openSession();//获取SqlSession ShopOrderAttrMapper shopOrderAttrMapper = sqlSession.getMapper(ShopOrderAttrMapper.class); //获取代理类 String orderId = shopOrderAttrMapper.selectOne("666655555555",30);//调用对应的方法 System.out.println(orderId); } catch (IOException e) { e.printStackTrace(); } } }
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 该方法会解析mybtis.xml并将所有的信息存到一个叫Configuration的对象中,后续所有的操作都跟该对象相关;
mybatis创建代理对象的流程:我们通过SqlSession获取Mapper的代理类,会委托给Configuration对象,然后configuration对象委托给MapperReistry对象,该对象里面有个knownMappes集合,该集合在解析mybtis.xml时,已经将对应的接口信息封装成MapperProxyFactory对象中,
因此,通过knownMappes可以得到一个MapperProxyFactory,该对象有个创建代理对象的方法,newInstance(),调用该方法先创建一个MapperProxy对象,该对象实现了InvocationHandler接口,因此在创建代理类时,将其作为参数传入得到代理类,
代理类的所有方法执行,都会被MapperProxy进行拦截
sql执行流程:由前面知道,Mapper对象因为动态代理,执行目标方法时,会被MapperProxy进行拦截,在拦截的方法里,会根据方法创建SqlCommand对象,然后根据该对象的类型调用SqlSession的对应方法,
底层会委托给Executor去执行,该对象最终调用PrepareStatment对象进行数据库的调用,得到结果交给ResultSetHandler进行处理
SqlCommand对象的创建:里面有2个属性,name是接口.方法名,如com.tft.User.selectOne type是sql的类型,如Select Update等
MethodSignature:方法签名:主要的逻辑是存储方法返回值的类型以及所有的参数Map<key为index,value为方法名>