Mybatis

mybatis框架概述:
mybatis是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql语句本身, 而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。 mybatis通过xml 或注解的方式将要执行的各种statement配置起来,并通过java对象和statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc进行了封装,屏蔽了 jdbc api 底层访问细节,使我 们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。

原理:Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

首先我们先看jdbc的代码

在这里插入图片描述
在这里插入图片描述

Mybatis核心思想
1、mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的信息。
2、mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
3、通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
4、SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
5、Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括HashMap集合对象、POJO对象类型。

mybatis映射文件

<?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:命名空间,它的作用就是对SQL进行分类化管理,可以理解为SQL隔离
	注意:使用mapper代理开发时,namespace有特殊且重要的作用
 -->
<mapper namespace="test">
	<!-- 
		[id]:statement的id,要求在命名空间内唯一  
		[parameterType]:入参的java类型
		[resultType]:查询出的单条结果集对应的java类型
		[#{}]: 表示一个占位符?
		[#{id}]:表示该占位符待接收参数的名称为id。注意:如果参数为简单类型时,#{}里面的参数名称可以是任意定义
	 -->
	<select id="findUserById" parameterType="int" resultType="com.gyf.domain.User">
		SELECT * FROM USER WHERE id = #{id}
	</select>
</mapper>

测试案列
在这里插入图片描述

这里总结关于DefaultSqlSession和SqlSessionTemplate

使用DefaultSqlSession完成update操作

public class DefaultSqlSessionTest {
    
    private static SqlSessionFactory sqlSessionFactory;

    static {
        initSqlSessionFactoryBySqlSessionFactoryBuilder();
    }

    /**
     * 通过 SqlSessionFactoryBuilder 创建 SqlSessionFactory
     */
    public static void initSqlSessionFactoryBySqlSessionFactoryBuilder(){
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        //返回的是DefaultSqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        HashMap<String, Object> paramMaps = Maps.newHashMap();
        paramMaps.put("name","hello");
        paramMaps.put("id","100");
        sqlSession.update("update",paramMaps);
        sqlSession.commit();
    }

由于默认情况下autoCommit是关闭的,所以此时若要通过显示的调用DefaultSqlSession的commit方法才能完成真正的更新。

使用SqlSessionTemplate完成update操作

public class SqlSessionTemplateTest {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
        HashMap<String, Object> paramMaps = Maps.newHashMap();
        paramMaps.put("name","hello");
        paramMaps.put("id","100");
        sqlSessionTemplate.update("update",paramMaps);
    }
}

通过上述代码可以发现,使用SqlSessionTemplate无需通过调用commit方法就可以完成真正的更新。那么它背后具体是怎么实现的呢我们进入源码发现当通过调用SqlSessionTemplate(SqlSessionFactory sqlSessionFactory)构造器new对象的时候,其最终内部通SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,PersistenceExceptionTranslator exceptionTranslator)来完成初始化,这个方法的关键是内部通过调用JDK Proxy.newProxyInstance方法创建了一个SqlSession代理对象并赋值给了sqlSessionProxy。此时,我们需要把目光聚焦到SqlSessionInterceptor的实现逻辑,因为其中包含该代理对象的代理逻辑,其代码逻辑如下:

private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      SqlSession sqlSession = getSqlSession(
          SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType,
          SqlSessionTemplate.this.exceptionTranslator);
      try {
        Object result = method.invoke(sqlSession, args);
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
          //执行commit
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
          sqlSession = null;
          Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
          if (translated != null) {
            unwrapped = translated;
          }
        }
        throw unwrapped;
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }

在代理逻辑中先通过getSqlSession方法获取sqlSession(该方法逻辑后续再展开讲),而后执行method.invoke方法,之后通过isSqlSessionTransactional方法判断当前操作是否是事务操作,如果属于事务操作则执行sqlSession的commit方法,以此完成了事务的提交。

主键返回之MySQL自增主键

<insert id="insertUser" parameterType="com.gyf.domain.User">
		<!-- 
			[selectKey标签]:通过select查询来生成主键
			[keyProperty]:指定存放生成主键的属性
			[resultType]:生成主键所对应的Java类型
			[order]:指定该查询主键SQL语句的执行顺序,相对于insert语句
			[last_insert_id]:MySQL的函数,要配合insert语句一起使用 -->
		<selectKey keyProperty="id" resultType="int" order="AFTER">
			SELECT LAST_INSERT_ID()
		</selectKey>
		<!-- 如果主键的值是通过MySQL自增机制生成的,那么我们此处不需要再显示的给ID赋值 -->
		INSERT INTO USER (username,sex,birthday,address) 
		VALUES(#{username},#{sex},#{birthday},#{address})
</insert>

parameterType和resultType
parameterType指定输入参数的java类型,可以填写别名或Java类的全限定名。
resultType指定输出结果的java类型,可以填写别名或Java类的全限定名。

#{}和${}
#{}:相当于预处理中的占位符?。
#{}里面的参数表示接收java输入参数的名称。
#{}可以接受HashMap、POJO类型的参数。
当接受简单类型的参数时,#{}里面可以是value,也可以是其他。
#{}可以防止SQL注入。
${}:相当于拼接SQL串,对传入的值不做任何解释的原样输出。
${}会引起SQL注入,所以要谨慎使用。
可 以 接 受 H a s h M a p 、 P O J O 类 型 的 参 数 。 当 接 受 简 单 类 型 的 参 数 时 , {}可以接受HashMap、POJO类型的参数。 当接受简单类型的参数时, HashMapPOJO{}里面只能是value。

selectOne和selectList
selectOne:只能查询0或1条记录,大于1条记录的话,会报错:
selectList:可以查询0或N条记录

MyBatis的Dao编写【mapper代理方式实现】
开发规范

  1. mapper接口的全限定名要和mapper映射文件的namespace的值相同。
  2. mapper接口的方法名称要和mapper映射文件中的statement的id相同;
  3. mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
  4. mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致;

mybatis的输入映射ParameterType
指定输入参数的java类型,可以使用别名或者类的全限定名。它可以接收简单类型,POJO对象、HashMap。

简单类型:
在这里插入图片描述

传递POJO对象
在这里插入图片描述

传递POJO包装对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
传递Map对象
在这里插入图片描述
在这里插入图片描述

输出映射 resultType/resultMap

resultType
使用resultType进行结果映射时,查询的列名和映射的pojo属性名完全一致,该列才能映射成功。
如果查询的列名和映射的pojo属性名全部不一致,则不会创建pojo对象;
如果查询的列名和映射的pojo属性名有一个一致,就会创建pojo对象。

输出简单类型
当输出结果只有一列时,可以使用ResultType指定简单类型作为输出结果类型
在这里插入图片描述

输出POJO列表
在这里插入图片描述
在这里插入图片描述
输出单个pojo对象和pojo列表时,mapper映射文件中的resultType的类型是一样的,mapper接口的方法返回值不同。
同样的mapper映射文件,返回单个对象和对象列表时,mapper接口在生成动态代理的时候,会根据返回值的类型,决定调用selectOne方法还是selectList方法。

resultMap
如果查询出来的列名和属性名不一致,通过定义一个resultMap将列名和pojo属性名之间作一个映射关系。
1、 定义resultMap
2、使用resultMap作为statement的输出映射类型
在这里插入图片描述

动态SQL
If标签:作为判断入参来使用的,如果符合条件,则把if标签体内的SQL拼接上。
(注意:用if进行判断是否为空时,不仅要判断null,也要判断空字符串‘’;)
Where标签:会去掉条件中的第一个and符号。

在这里插入图片描述

SQL片断
Mybatis提供了SQL片段的功能,可以提高SQL的可重用性。
在这里插入图片描述
foreach 遍历
在这里插入图片描述

Mybatis和Spring的整合
spring中配置

<!-- 引入配置文件 -->  
    <bean id="propertyConfigurer"  
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
        <property name="location" value="classpath:jdbc.properties" />  
    </bean>  

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"  
        destroy-method="close">  
        <property name="driverClassName" value="${driver}" />  
        <property name="url" value="${url}" />  
        <property name="username" value="${username}" />  
        <property name="password" value="${password}" />  
        <!-- 初始化连接大小 -->  
        <property name="initialSize" value="${initialSize}"></property>  
        <!-- 连接池最大数量 -->  
        <property name="maxActive" value="${maxActive}"></property>  
        <!-- 连接池最大空闲 -->  
        <property name="maxIdle" value="${maxIdle}"></property>  
        <!-- 连接池最小空闲 -->  
        <property name="minIdle" value="${minIdle}"></property>  
        <!-- 获取连接最大等待时间 -->  
        <property name="maxWait" value="${maxWait}"></property>  
    </bean>  
    
    <!-- spring和MyBatis整合,不需要mybatis的配置映射文件 -->  
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSource" />  
        <!-- 自动扫描mapping.xml文件 -->  
        <property name="mapperLocations" value="classpath:com/sgcc/user/mapping/*.xml"></property>  
    </bean>  
    
    <!-- DAO接口所在包名,Spring会自动查找其下的类 动态代理实现 不用写dao的实现类-->  
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
        <property name="basePackage" value="com.sgcc.user.dao" />  
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>  
    </bean>  
    
    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->  
    <bean id="transactionManager"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean>  

    <tx:annotation-driven transaction-manager="transactionManager"/>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值