Mybatis

 

一、主要类

SqlSessionFactoryBuilder:读取配置信息创建SqlSessionFactory,建造者模式,方法级别生命周期,创建SqlSessionFactory后回收

SqlSessionFactory:创建Sqlsession,工厂单例模式,存在于程序的整个生命周期;

SqlSession:代表一次数据库连接,可以直接发送SQL执行,也可以通过调用 ,Mapper访问数据库;线程不安全,要保证线程独享(方法级);

SQL Mapper:由一个Java接口和XML文件组成,包含了要执行的SQL语句和结果集映射规则。方法级别生命周期;

 二、一对一,一对多关联查询(association,collection标签

 嵌套结果关联,使用一个sql将结果拼接起来。

<resultMap id="userPositionResultMap" type="com.bean.User">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <association property="position" javaType="com.bean.Position" > 
            <id column="position_id" property="id"/>
            <result column="position_name" property="name"/>
        </association>
</resultMap>

嵌套查询关联,执行多个sql,返回结果(推荐,使用懒加载,按需加载)

<resultMap id="userPositionResultMap" type="com.bean.user">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <association property="position" column="position_id" select="com.mapping.positionMapping.selectById"> //column为向select中传入的参数
        </association>
</resultMap>

第一个sql只查询user的信息(包含position_id)返回userPositionResultMap,第二个sql (com.mapping.positionMapping.selectById)根据ID查询属性,根据userPositionResultMap中关联的association自动查询关联sql数据放入position中。

column多个参数时column="{id=position_id,name=position_name}"。

存在N+1 的问题,使用fetchType = "lazy" 进行按需加载,使用到的时候再去执行关联查询(全局的配置aggressiveLazyLoading也需设置成false,true:懒加载对象被懒属性全部加载,false:每个属性都按需加载)

一对多将标签改为collection即可。

三、springBoot 配置myBatis

#配置mysql数据源
spring.datasource.url=jdbc:mysql://your-mysql-url/database-name?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driverClassName=com.mysql.jdbc.Driver

#security.basic.enabled=false

mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl


## Mybatis 配置
mybatis.type-aliases-package=com.test.model
mybatis.mapper-locations=classpath:mapper/*.xml
#使全局的映射器启用或禁用缓存。
mybatis.configuration.cache-enabled=true
#全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。
mybatis.configuration.lazy-loading-enabled=true
#当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。
mybatis.configuration.aggressive-lazy-loading=true
#是否允许单条sql 返回多个数据集  (取决于驱动的兼容性) default:true
mybatis.configuration.multiple-result-sets-enabled=true
#是否可以使用列的别名 (取决于驱动的兼容性) default:true
mybatis.configuration.use-column-label=true
#允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。  default:false
mybatis.configuration.use-generated-keys=true
#指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射\u3000PARTIAL:部分  FULL:全部
mybatis.configuration.auto-mapping-behavior=partial
#这是默认的执行类型  (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新)
mybatis.configuration.default-executor-type=simple
#使用驼峰命名法转换字段。
mybatis.configuration.map-underscore-to-camel-case=true
#设置本地缓存范围 session:就会有数据的共享  statement:语句范围 (这样就不会有数据的共享 ) defalut:session
mybatis.configuration.local-cache-scope=session
#设置但JDBC类型为空时,某些驱动程序 要指定值,default:OTHER,插入空值时不需要指定类型
mybatis.configuration.jdbc-type-for-null=null
#如果数据为空的字段,则该字段省略不显示,可以通过添加配置文件,规定查询数据为空是则返回null。
mybatis.configuration.call-setters-on-nulls=true

 四、鉴别器

 根据某字段返回不同的resultMap(根据sex字段,1返回boyResultMap,2返回grilResultMap)

<resultMap id="userResultMap" type="com.bean.user">
        <discriminator column="sex" javaType="int"> 
                <case values="1" resultMap="boyResultMap">
                <case values=2" resultMap="grilResultMap">
        </discriminator >
</resultMap>    

 

boyResultMap与grilResultMap需继承userResultMap并且type为com.bean.user

五、缓存

  一级缓存,默认开启,select 上配置flushCache = "true"会关闭一级缓存(不建议关闭)

 存在于SqlSession的生命周期中(方法级,线程不共享),用MAP缓存数据,会将方法、参数、SQl等信息通过算法存入键值key(方法和参数一项变了,就不会走缓存),执行结果存入value中;

key为CacheKey对象,影响CacheKey有以下几个因素:1、mappedStatment的id也就是namespace+方法名 2、分页信息 3、查询所使用的sql语句 4、传递给SQL的实际参数值;

CacheKey中有个list插入以上因素,除了判断hash值最后也要判断list顺序是否一致

增删改的操作都会清空缓存。

二级缓存,存在于SqlSessionFactory,是以namespace为单位的(xml里配置,也就是mapper文件),不同namespace下的操作互不影响

<mapper namespace="com.gxever.mdp.res.DissemResourceMapper">  namespace

在mapping.xml中增加<cache eviction="FIFO" flishInterval="60000" size="512" readOnly="true"/>标签开启二级缓存(配置先进先出,失效时间,存储空间,只读),增删改也都会刷新二级缓存

二级缓存容易出现在脏读,避免使用二级缓存,推荐使用redis类似的缓存。不同namespace,有两个相同的二级缓存,修改一个namespace的二级缓存,另一个二级缓存数据还是不会变。

访问顺序

 先访问二级缓存查找,二级缓存找不到再从一级缓存中找,最后在数据库里找‘’

 

六、mybatis 数据源

资料: https://my.oschina.net/mengyuankan/blog/2664784     (博主有很多值得学习的博客)

我们已一段mybatis的配置文件为例

复制代码
<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <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>
复制代码

datasource的type共有三个选项

UNPOOLED    不使用连接池的数据源

POOLED      使用连接池的数据源

JNDI        使用JNDI实现的数据源

通过工厂模式,反射生成一个DatasourceFactory。去创建datasource

这里DataSourceFactory有三个子类,也就是上述三个datasource的类型。

 

 

unpooledDatasourceFactory(非连接池)再通过getConnection去生成connection

pooledDatasourceFactory(数据库连接池): poolConnection使用动态代理封装了真正的数据库连接对象(做了增强)

七、加载JDBC驱动

  Class.forName("com.mysql.jdbc.Driver");

   这样可以加载驱动是因为,com.mysql.jdbc.Driver中有段静态代码块去加载了驱动

  

static{
    try{
        java.sql.DriverManager.registerDriver(new Driver());
    } catch{
        ...
    }
}

 八、初始化过程

  https://www.jianshu.com/p/7bc6d3b7fb45

九、binding模块

  https://www.jianshu.com/p/83785a294f8e

十、运作过程

 

posted @ 2019-05-27 16:08  乔儿的终极小迷弟  阅读(308)  评论(0编辑  收藏  举报