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
十、运作过程