【思维导图】mybatis-持久层框架设计实现及MyB源码分析
mybatis入门教程-Mybatis简介与原理
【持久化框架】Mybatis简介与原理--夜半什么是Mybatis资料官网:https://mybatis.github.io/mybatis-3/zh/index.html/MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。
MyBatis 提供的持久层框架包括SQL Maps和Data Access Objects(DAO)。
MyBatis 是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。
MyBatis 避免了几乎所有的JDBC 代码和手工设置参数以及抽取结果集。
MyBatis使用简单的XML 或注解来配置和映射基本体,将接口和Java 的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
1、mybatis ibatis2、主要是做数据库操作,使用java操作数据库,dao[持久化]技术知识点1、概念2、基本CRUD标签3、动态sql4、一对多,多对一关系5、了解注解式配置学习内容1、理解什么是mybatis,以及mybatis的应用场景2、使用mybatis开发demo3、熟悉mybatis的配置文件,以后spring的时候,没有用。
4、会使用mybatis实现简单增删改查①Insert delete update select 标签使用ORM对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
从效果上说,它其实是创建了一个可在编程语言里使用的--“虚拟对象数据库”。
基于Java的Mybaits生成持久层配置文件
基于Java的Mybaits生成持久层配置文件作者:管才路叶刚耿伟王立河来源:《电子技术与软件工程》2018年第22期摘要系统开发过程中,需要根据客户提出的需求对业务数据进行分析与统计。
数据库是用于存储数据的仓库,在系统的开发过程中,开发者往往会将数据以关系表形式存于关系数据库中,因此开发者会频繁的操作数据库。
在数据库框架还未成熟的早期,程序员经常是通过JDBC与数据库建立联系,此过程中会出现大量重复工作。
此种情况下,持久层框架(所谓持久层指的数据存于磁盘中,轻易不会丢失)应运而生,现在经常用的框架有Mybaits,iBatis,Hibernate等等,通过框架生成诸多的配置文件,避免了许许多多的重复工作。
本文主要针对Mvbaits持久层框架关于生成数据表的相关配置文件(如:mapper.xml,mapper.java以及关系表对应的实体类文件)这一操作通过Java后台实现。
【关键词】Mybaits mysql maven1 Mybatis-Generator工具在Web开发过程中我们经常会使用Mybatis持久层框架完整数据访问层(dao层)开发,此框架有一个配置文件生成工具Mybatis-Generator。
其可以通过命令与简单的配置,帮助开发者完成dao成相关文件的开发。
以下是使用方法以及对其进行轻微改造:(1)下载Mybatis-Generator代码生成工具(解压,解压后里面会有src、generatorConfig.xml. mybatis-generator-core-1.3.1 .jar文件或者文件夹);(2)在generatorConfig .xml配置参数:location(连接数据的jar),数据源,表名,dao 层文件路径等;(3)执行command命令:“java -jarmybatis-generator-core-l .3.1.j ar -configfilegeneratorConfig.xml -overwrite".通过上述步骤即可完成dao层文件的生成,在此为了方便可以在解压后的文件夹下对command命令做成服务,在此命名为generator.bat。
MyBatis思维导图
MyBatis思维导图1、初识框架技术2、搭建MyBatis环境3、掌握MyBatis的核⼼API4、掌握MyBatis的核⼼配置⽂件:主要⽤于配置数据库连接和MyBatis运⾏时所需的各种特性5、掌握SQL映射⽂件(或者使⽤⾃动⽣成SQL映射⽂件的插件)6、掌握MyBatis缓存7、Dao上级操作8、掌握动态SQL9、掌握MyBatis框架的优缺点和其使⽤场合--------------------------------------------------------------------------------------------------------------------------------------知识点详情-------------------------------------------------------------1、初识框架技术 1.1什么是框架 框架(Framework)是⼀个提供了可重⽤的公共结构的半成品,它成为构建新的应⽤程序提供了极⼤的便利,更提供了可重⽤的设计; 1.2当前的主流框架 1.2.1 Struts2: Struts2以Webwork设计思想为核⼼,吸收了Struts框架的部分优点,提供了⼀个更加整洁的基于MVC设计模式实现的Web应⽤程序框架。
它引⼊了⼏个新的框架特性:从逻辑中分离出横切关注点的拦截器,减少或者消除配置⽂件,贯穿整个框架的强⼤表达式语⾔,⽀持可重⽤的标签API等。
Struts2充分利⽤了从其他MVC框架学到的经验和教训,使整个框架更加清晰、灵活(引⼊了拦截器)。
1.2.2 Hibernate: Hibernate是⼀个优秀的持久化框架(ORM),负责简化将对象数据保存到数据库中,或从数据库中读取数据并封装到对象的⼯作。
Hibernate通过简单配置和编码即可替代JDBC繁琐的程序代码。
1.2.3Spring: Spring是⼀个开源框架。
mybatis的原理
mybatis的原理MyBatis是一款支持Java语言的持久层框架,它的原理是通过提供一种将Java对象与数据库表进行映射的方式,实现对数据库的操作和访问。
MyBatis的原理主要有以下几个方面:1. SQL映射文件:MyBatis使用XML文件来配置SQL语句和结果映射,这些XML文件被称为SQL映射文件。
在这些映射文件中,可以定义各种SQL语句,包括查询、更新、插入和删除等操作。
2. 数据源配置:MyBatis需要连接数据库来进行操作,所以需要配置数据源信息。
数据源可以是数据库连接池,也可以是直接连接数据库。
在配置数据源时,需要指定数据库的连接信息,例如URL、用户名、密码等。
3. SQLSession:MyBatis通过SQLSession来执行SQL语句。
SQLSession是MyBatis与数据库交互的核心类,它提供了各种方法来执行SQL语句,并返回结果。
SQLSession可以通过SqlSessionFactory来创建,而SqlSessionFactory可以通过XML配置文件或Java代码来创建。
4. SQL语句执行:在SQLSession中执行SQL语句时,MyBatis会将SQL语句发送给数据库执行,并将结果返回。
MyBatis支持各种类型的SQL语句,例如简单的查询语句、动态SQL语句以及存储过程等。
5. 参数绑定和结果映射:在执行SQL语句时,MyBatis可以将Java对象与SQL语句中的参数进行绑定,以实现参数传递。
同时,MyBatis还可以将查询结果与Java对象进行映射,以便于操作和使用。
6. 缓存机制:MyBatis提供了缓存机制,可以缓存查询的结果,提高查询性能。
缓存可以分为一级缓存和二级缓存。
一级缓存是基于SqlSession的缓存,而二级缓存是基于SqlSessionFactory的缓存。
总的来说,MyBatis的原理是通过SQL映射文件配置SQL语句和结果映射,使用SQLSession执行SQL语句,并通过参数绑定和结果映射与Java对象进行交互,同时支持缓存机制来提高性能。
TKmybatis的框架介绍和原理分析及Mybatis新特性
TKmybatis的框架介绍和原理分析及Mybatis新特性tkmybatis是在mybatis框架的基础上提供了很多⼯具,让开发更加⾼效,下⾯来看看这个框架的基本使⽤,后⾯会对相关源码进⾏分析,感兴趣的同学可以看⼀下,挺不错的⼀个⼯具实现对员⼯表的增删改查的代码java的dao层接⼝1. public interface WorkerMapper extends Mapper<Worker> {2. }xml映射⽂件1. <?xml version="1.0" encoding="UTF-8"?>2. <!DOCTYPE mapper PUBLIC "-////DTD Mapper3.0//EN" "/dtd/mybatis-3-mapper.dtd">3. <mapper namespace="com.jjs.kaiwen.dao.WorkerMapper">4. <resultMap id="BaseResultMap" type="com.jjs.kaiwen.model.Worker">5. <!--6. WARNING - @mbggenerated7. -->8. <id column="id" jdbcType="INTEGER" property="id" />9. <result column="worker_id" jdbcType="VARCHAR" property="workerId" />10. <result column="name" jdbcType="VARCHAR" property="name" />11. <result column="org_id" jdbcType="INTEGER" property="orgId" />12. <result column="status" jdbcType="VARCHAR" property="status" />13. <result column="role_id" property="roleId" jdbcType="INTEGER" />14. </resultMap>15. </mapper>实体对象1. @Table(name = "worker")2. public class Worker {3. @Id4. @GeneratedValue(strategy = GenerationType.IDENTITY)5. private Integer id;6.7. @Column(name = "worker_id")8. private String workerId;9.10. private String name;11.12. @Column(name = "org_id")13. private Integer orgId;14.15. private String status;16.17. @Column(name = "role_id")18. private Integer roleId;19.20. // getters and setters ...21. }以上就是实现对Worker进⾏增删改查的所有代码,包括选择性更新、插⼊、删除等,所有的⽅法列表如下以后对表字段的添加或修改只需要更改实体对象的注解,不需要修改xml映射⽂件,如将worker_id改成worker_no1. @Column(name = "worker_no")2. private String workerNo;数据源的配置,只需要将org.mybatis.spring.mapper.MapperScannerConfigurer改成tk.mybatis.spring.mapper.MapperScannerConfigurer,然后加⼀个属性,也可不加,因为框架提供了默认实现1. <bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">2. <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />3. <property name="basePackage" value="com.jjs.zanbi.dao" />4. <property name="properties">5. <value>6. mappers=mon.Mapper7. </value>8. </property>9. </bean>⽤这个库之后写代码感觉在飞…….如果只是简单的了解此框架到这⾥就可以了,下⾯是对框架实现原理的分析原理的简单分析此框架为我们实现这些功能所有的改动都在Mapper层⾯,所有的Mapper都继承了mon.Mapperpublic interface WorkerMapper extends Mapper<Worker> {}Mapper接⼝的声明如下,可以看到Mapper接⼝实现了所有常⽤的⽅法1. public interface Mapper<T> extends2. BaseMapper<T>,3. ExampleMapper<T>,4. RowBoundsMapper<T>,5. Marker {6.7. }看⼀下完整的UML图,太⼤了,可以⽤新窗⼝打开,放⼤之后再看这⾥选择⼀个接⼝:SelectOneMapper接⼝,对于源码进⾏简单分析,此接⼝声明如下:4. * 根据实体中的属性进⾏查询,只能有⼀个返回值,有多个结果是抛出异常,查询条件使⽤等号5. *6. * @param record7. * @return8. */9. @SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL")10. T selectOne(T record);11.12. }@SelectProvider是mybatis3之后提供的,⽤于灵活的设置sql来源,这⾥设置了服务提供类和⽅法,但这个库并没有直接⽤method指定的⽅法来返回sql,⽽是在运⾏时进⾏解析的,代码如下1. public class BaseSelectProvider extends MapperTemplate {2.3. public String selectOne(MappedStatement ms) {4. Class<?> entityClass = getEntityClass(ms);5. //修改返回值类型为实体类型6. setResultType(ms, entityClass);7. StringBuilder sql = new StringBuilder();8. sql.append(SqlHelper.selectAllColumns(entityClass));9. sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));10. sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));11. return sql.toString();12. }13. }到这⾥我们就⼤概知道了这个库为我们提供便利的原理了,总的来说就是这个库帮我们提供了对表的基本操作的sql,帮我们省了很多⼯作量,⽽且维护起来也很⽅便,否则我们的xml⽂件动不动就⼏百⾏甚⾄上千⾏对源码的探索不能到这⾥停⽌,最起码要分析到与另⼀个框架的整合点我们知道,mybatis的mapper接⼝是在启动的时候被框架以JdkProxy的形式封装了的,具体对应的类是MapperFactoryBean,这个类中有⼀个checkDaoConfig()⽅法,是从⽗类继承并重写了该⽅法,继承结构如下MapperFactoryBean -> SqlSessionDaoSupport -> DaoSupport这⾥的DaoSupport就是spring提供的Dao的抽象,代码如下1. public abstract class DaoSupport implements InitializingBean {2.3. // spring 完成属性设置后会调⽤此⽅法4. @Override5. public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {6. // 这⾥提供了接⼝供⼦类去实现7. checkDaoConfig();8.9. // Let concrete implementations initialize themselves.10. try {11. initDao();12. }13. catch (Exception ex) {14. throw new BeanInitializationException("Initialization of DAO failed", ex);15. }16. }17.18. protected abstract void checkDaoConfig() throws IllegalArgumentException;19.20. protected void initDao() throws Exception {21. }22.23. }框架⾃定义的MapperFactoryBean重写了checkDaoConfig()⽅法,完成对所有sql语句的设置,代码如下1. @Override2. protected void checkDaoConfig() {3. super.checkDaoConfig();4. //通⽤Mapper5. if (mapperHelper.isExtendCommonMapper(getObjectType())) {6. //这⾥去处理该类所对应的MappedStatement,封装在helper类中处理7. mapperHelper.processConfiguration(getSqlSession().getConfiguration(), getObjectType());8. }9. }MapperHelper的processConfiguration⽅法如下1. public void processConfiguration(Configuration configuration, Class<?> mapperInterface) {2. String prefix;3. if (mapperInterface != null) {4. prefix = mapperInterface.getCanonicalName();5. } else {6. prefix = "";7. }8. for (Object object : new ArrayList<Object>(configuration.getMappedStatements())) {9. if (object instanceof MappedStatement) {10. MappedStatement ms = (MappedStatement) object;11. //检查这个MappedStatement是否属于此映射对象12. if (ms.getId().startsWith(prefix) && isMapperMethod(ms.getId())) {13. if (ms.getSqlSource() instanceof ProviderSqlSource) {14. //去设置该statement的sql语句15. setSqlSource(ms);16. }17. }18. }19. }20. }设置sql的逻辑,提供了⼏种不同类型的sqlsource1. public void setSqlSource(MappedStatement ms) throws Exception {6. try {7. //第⼀种,直接操作ms,不需要返回值8. if (method.getReturnType() == Void.TYPE) {9. method.invoke(this, ms);10. }11. //第⼆种,返回SqlNode12. else if (SqlNode.class.isAssignableFrom(method.getReturnType())) {13. SqlNode sqlNode = (SqlNode) method.invoke(this, ms);14. DynamicSqlSource dynamicSqlSource = new DynamicSqlSource(ms.getConfiguration(), sqlNode);15. setSqlSource(ms, dynamicSqlSource);16. }17. //第三种,返回xml形式的sql字符串18. else if (String.class.equals(method.getReturnType())) {19. String xmlSql = (String) method.invoke(this, ms);20. SqlSource sqlSource = createSqlSource(ms, xmlSql);21. //替换原有的SqlSource22. setSqlSource(ms, sqlSource);到这⾥整个sql的获取流程就分析完了,本⼈⽤这个库写过⼀个⼩项⽬,确实节省了开发的⼯作量,⽽且DAO层的结构更加清晰简洁了关于mybatis新特性从3.4.0开始,mybatis提供对外部表的alias引⽤⽅法,多表联合查询就⽅便多了,我们先看原始的⽅式是怎样做的1. select a.id,,b.bid,b.bname .....2. from user a3. left join room b原始的⽅式是将所有的表字段列出来,再来看⽤新特性怎样做1. select id="selectUsers" resultType="map">2. select3. <include refid="user_col_sql_id"><property name="alias" value="t1"/>,4. <include refid="room_col_sql_id"><property name="alias" value="t2"/>5. from user t16. left join room t27. </select>这⾥主要就是对基本的sql进⾏了复⽤,如果对表进⾏了修改只要在原始的sql节点修改就可以了,就算是5个表的联合查询,sql也是清晰易懂,维护起来会更轻松新版本的mybatis对于对象映射也提供了更友好的⽅式,直接使⽤外部的ResultMap再加上查询语句中的别名就映射完成了1. <resultMap id="workerResultMap" type="com.jjs.kaiwen.model.Worker" extends="BaseResultMap">2. <association property="room" columnPrefix="b_" resultMap="Mapper.BaseResultMap"/>3. </resultMap>更进⼀步敏锐的程序员可能会提出问题,如当多表查询的时候可能会存在字段名称相同的情况,这⾥的解决⽅案是给include添加另⼀个属性1. <include refid="user_col_sql_id_with_alias">2. <property name="alias" value="t"/>3. <property name="prefix" value="t_"/>4. </include>包含prefix的sqlNode如下1. <sql id="base_column_with_alias">2. ${alias}.ID as ${prefix}ID,3. ${alias}.WORKER_ID as ${prefix}WORKER_ID,4. ${alias}.NAME as ${prefix}NAME,5. ${alias}.ZB_ROLE_ID as ${prefix}ZB_ROLE_ID,6. ${alias}.ORG_ID as ${prefix}ORG_ID,7. ${alias}.STATUS as ${prefix}STATUS8. </sql>如果说觉得⼿动写包含alias和prefix的字段⿇烦,可以⽤,mybatis代码⽣成器的插件的⽅式实现,我⾃⼰写了⼀个⽣成器的插件,可以通⽤Service类1. /**2. * Created by Kaiwen3. */4. @Service5. public abstract class CommonServiceImpl<T,PK extends Serializable> implements CommonService<T,PK> {6. /**7. * 泛型注⼊8. */9. @Autowired10. private Mapper<T> mapper;11.12. public T selectByPrimaryKey(PK entityId) {13.14. return mapper.selectByPrimaryKey(entityId);15. }16.17. public int deleteByPrimaryKey(PK entityId) {18. return mapper.deleteByPrimaryKey(entityId);19. }20.21. public int insert(T record) {22. return mapper.insert(record);23. }24.25. public int insertSelective(T record) {26. return mapper.insertSelective(record);27. }28.29. public int updateByPrimaryKeySelective(T record) {30. return mapper.updateByPrimaryKeySelective(record);31. }32.33. public int updateByPrimaryKey(T record) {38. return mapper.selectByExample(example);39. }40. }注⼊⽅式区别1. <bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">2. <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />3. <property name="basePackage" value="com.jjshome.esf.core.dao.school" />4. <property name="properties">5. <value>6. mappers=mon.Mapper7. </value>8. </property>9. </bean>10.11.12. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">13. <property name="basePackage" value="munity,com.jjshome.esf.core.dao.hsl"/>14. </bean><实体类1. package mon.entity.school;2.3. import java.util.Date;4. import javax.persistence.*;5.6. @Table(name = "XQ_SCHOOL_AREA")7. public class SchoolArea {8. /**9. * 主键ID10. */11. @Id12. @Column(name = "ID")13. private Integer id;14.15. /**16. * 城市编码17. */18. @Column(name = "CITY_CODE")19. private String cityCode;20.21. /**22. * 学区名称23. */24. @Column(name = "NAME")25. private String name;26.27. /**28. * 学区名称拼⾳29. */30. @Column(name = "NAME_SPELL")31. private String nameSpell;32.33. /**34. * 状态,1:正常,0:删除35. */36. @Column(name = "STATUS")37. private Byte status;38.39. /**40. * 添加⼈41. */42. @Column(name = "CREATE_ID")43. private String createId;44.45.46. @Transient47. private Integer primaryCount; //⼩学数量48. @Transient49. private Integer middleCount; //初中数量50. @Transient51. private Integer highCount;//⾼中数量TK mybatis Mapper⽂件内容1. <?xml version="1.0" encoding="UTF-8" ?>2. <!DOCTYPE mapper PUBLIC "-////DTD Mapper3.0//EN" "/dtd/mybatis-3-mapper.dtd" >3. <mapper namespace="com.jjshome.esf.core.dao.school.ISchoolAreaDAO" >4. <resultMap id="BaseResultMap" type="mon.entity.school.SchoolArea" >5. <!--6. WARNING - @mbggenerated7. -->8. <id column="ID" property="id" jdbcType="INTEGER" />9. <result column="CITY_CODE" property="cityCode" jdbcType="VARCHAR" />10. <result column="NAME" property="name" jdbcType="VARCHAR" />11. <result column="NAME_SPELL" property="nameSpell" jdbcType="VARCHAR" />12. <result column="STATUS" property="status" jdbcType="TINYINT" />13. <result column="CREATE_ID" property="createId" jdbcType="VARCHAR" />14. <result column="CREATE_DATE" property="createDate" jdbcType="TIMESTAMP" />15. <result column="UPDATE_ID" property="updateId" jdbcType="VARCHAR" />16. <result column="UPDATE_DATE" property="updateDate" jdbcType="TIMESTAMP" />17. <result column="CITY_NAME" property="cityName"/>18. <result column="PRIMARY_COUNT" property="primaryCount"/>19. <result column="MIDDLE_COUNT" property="middleCount"/>20. <result column="HIGH_COUNT" property="highCount"/>21. </resultMap>22.23. <resultMap id="SchoolDetailArea" type="mon.entity.school.SchoolAreaDetail"24. extends="com.jjshome.esf.core.dao.school.ISchoolInfoDAO.SchoolInfo">30. SELECT A.*, AS CITY_NAME,31. (SELECT COUNT(*) FROM XQ_SCHOOL_INFO B WHERE A.ID=B.AREA_ID AND B.TYPE='553' AND B.STATUS = 1 ) AS PRIMARY_COUNT,32. (SELECT COUNT(*) FROM XQ_SCHOOL_INFO B WHERE A.ID=B.AREA_ID AND B.TYPE='554' AND B.STATUS = 1 ) AS MIDDLE_COUNT,33. (SELECT COUNT(*) FROM XQ_SCHOOL_INFO B WHERE A.ID=B.AREA_ID AND B.TYPE='555' AND B.STATUS = 1 ) AS HIGH_COUNT34. FROM XQ_SCHOOL_AREA A35. LEFT JOIN YW_CITY_SETTING C ON A.CITY_CODE = C.CODE36. <where>37. <if test="name != null and name != '' "> LIKE CONCAT('%',#{NAME},'%') </if>38. <if test="areaCityCode != null and areaCityCode != '' "> A.CITY_CODE = #{areaCityCode} </if>39. <if test="keywords != null and keywords != '' ">40. ( LIKE CONCAT('%',#{keywords},'%')41. )42. </if>43. </where>44. </select>45.46.47. <select id="selectAreaIdAndKeyWord" parameterType="java.util.Map" resultMap="BaseResultMap">48. SELECT49. *50. FROM51. XQ_SCHOOL_AREA52. WHERE53. 1=154. <if test="cityId != null">55. AND CITY_CODE=#{cityId}56. </if>57. <if test="key != null and key!=''">58. AND (NAME like CONCAT(#{key},'%' ) or NAME_SPELL like CONCAT(#{key},'%' ))59. </if>60. AND61. STATUS=162. <if test="pageSize != null">63. limit #{pageSize}64. </if>65. </select>66.67.68. <!--查询学区详情列表-->69. <select id="selectAreaDetailByPage" parameterType="map" resultMap="SchoolDetailArea">70.71. SELECT A.* , AS SCHOOL_AREA_NAME , AS CITY_NAME, AS AREA_NAME FROM XQ_SCHOOL_INFO A72. LEFT JOIN XQ_SCHOOL_AREA B ON A.AREA_ID = B.ID73. LEFT JOIN YW_CITY_SETTING C ON A.CITY_CODE = C.CODE74. LEFT JOIN YW_CITY_SETTING D ON A.AREA_CODE = D.CODE75.76. WHERE A.STATUS = 1 AND B.STATUS =177. <if test="areaId != null and areaId.length() > 0"> AND A.AREA_ID = #{areaId} </if>78. <if test="typeList != null and typeList.size > 0">79. AND80. A.TYPE IN81. <foreach collection="typeList" item="item" index="index" open="(" close=")" separator=",">82. #{item}83. </foreach>84. </if>85. <if test="name != null and name != '' "> AND LIKE CONCAT('%',#{name},'%') </if>86. </select>87.88. </mapper>普通mybatisMapper⽂件1. <?xml version="1.0" encoding="UTF-8" ?>2. <!DOCTYPE mapper PUBLIC "-////DTD Mapper3.0//EN" "/dtd/mybatis-3-mapper.dtd" >3. <mapper namespace="com.jjshome.esf.core.dao.school.ISchoolInfoDAO">4. <resultMap id="SchoolInfo" type="mon.entity.school.SchoolInfo">5. <id column="ID" property="id"/>6. <result column="NAME" property="name"/>7. <result column="NAME_SPELL" property="nameSpell"/>8. <result column="ALIAS" property="alias"/>9. <result column="ALIAS_SPELL" property="aliasSpell"/>10. <result column="TYPE" property="type" typeHandler="ponent.handler.DictValueTypeHandler"/>11. <result column="AREA_ID" property="areaId"/>12. <result column="CITY_CODE" property="cityCode"/>13. <result column="AREA_CODE" property="areaCode"/>14. <result column="ADDR" property="addr"/>15. <result column="START_TIME" property="startTime"/>16. <result column="MOTTO" property="motto"/>17. <result column="WEB_SITE" property="webSite"/>18. <result column="PHONE" property="phone"/>19. <result column="FEATURE" property="feature" typeHandler="ponent.handler.DictValueListTypeHandler"/>20. <result column="LNG" property="lng"/>21. <result column="LAT" property="lat"/>22. <result column="UNIT_PRICE" property="unitPrice"/>23. <result column="SALE_PRICE" property="salePrice"/>24. <result column="NATURE_TYPE" property="natureType" typeHandler="ponent.handler.DictValueTypeHandler"/>25. <result column="NATURE_CITY" property="natureCity" typeHandler="ponent.handler.DictValueTypeHandler"/>26. <result column="SCHOOL_DEGREE" property="schoolDegree"/>27. <result column="ENROL_DEGREE" property="enrolDegree"/>28. <result column="IMG_DEGREE" property="imgDegree"/>29. <result column="STATUS" property="status"/>30. <result column="CREATE_ID" property="createId"/>31. <result column="CREATE_DATE" property="createDate"/>32. <result column="UPDATE_ID" property="updateId"/>33. <result column="UPDATE_DATE" property="updateDate"/>34.35. <result column="CITY_NAME" property="cityName" />36. <result column="AREA_NAME" property="areaName" />37. <result column="SCHOOL_DISTRICT_NAME" property="schoolDistrictName" />38. <result column="SALE_COUNT" property="saleCount" />39. </resultMap>40.41. <sql id="Base_Column_List">46. ALIAS_SPELL,47. TYPE,48. AREA_ID,49. CITY_CODE,50. AREA_CODE,51. ADDR,52. START_TIME,53. MOTTO,54. WEB_SITE,55. PHONE,56. FEATURE,57. LNG,58. LAT,59. UNIT_PRICE,60. SALE_PRICE,61. NATURE_TYPE,62. NATURE_CITY,63. SCHOOL_DEGREE,64. ENROL_DEGREE,65. IMG_DEGREE,66. STATUS,67. CREATE_ID,68. CREATE_DATE,69. UPDATE_ID,70. UPDATE_DATE,71. SALE_COUNT,72. SALE_COUNT73. </sql>74.75. <select id="selectById" resultMap="SchoolInfo" parameterType="ng.Integer">76. SELECT77. i.*,78. as 'CITY_NAME',79. as 'AREA_NAME',80. as 'SCHOOL_DISTRICT_NAME'81. FROM82. XQ_SCHOOL_INFO i83. LEFT JOIN YW_CITY_SETTING yc ON i.CITY_CODE = yc.CODE84. LEFT JOIN YW_CITY_SETTING ya ON i.AREA_CODE = ya.CODE85. LEFT JOIN XQ_SCHOOL_AREA xq ON i.AREA_ID = xq.ID86. WHERE87. i.ID = #{id,jdbcType=INTEGER}88. </select>89.90. <delete id="deleteById" parameterType="java.util.Map">91. UPDATE92. XQ_SCHOOL_INFO93. SET94. STATUS = 0,95. UPDATE_ID = #{updateId},96. UPDATE_DATE = NOW()97. WHERE98. ID = #{id,jdbcType=INTEGER}99. </delete>100.101. <delete id="batchDeleteByIds" parameterType="java.util.Map">102. UPDATE103. XQ_SCHOOL_INFO104. SET105. STATUS = 0,106. UPDATE_ID = #{updateId},107. UPDATE_DATE = NOW()108. WHERE109. ID IN (${ids})110. </delete>111.112. <update id="deleteAreaRelation" parameterType="mon.entity.school.SchoolInfo"> 113. update XQ_SCHOOL_INFO114. SET AREA_ID = NULL,115. UPDATE_DATE = NOW()116. WHERE117. ID = #{id}118. </update>119.120. <insert id="insert" parameterType="mon.entity.school.SchoolInfo">121. <selectKey resultType="Integer" keyProperty="id">122. SELECT LAST_INSERT_ID()123. </selectKey>124. INSERT INTO XQ_SCHOOL_INFO125. (NAME,126. NAME_SPELL,127. ALIAS,128. ALIAS_SPELL,129. TYPE,130. AREA_ID,131. CITY_CODE,132. AREA_CODE,133. ADDR,134. START_TIME,135. MOTTO,136. WEB_SITE,137. PHONE,138. FEATURE,139. LNG,140. LAT,141. UNIT_PRICE,142. SALE_PRICE,143. NATURE_TYPE,144. NATURE_CITY,145. SCHOOL_DEGREE,146. ENROL_DEGREE,147. IMG_DEGREE,148. STATUS,154. (#{name,jdbcType=VARCHAR},155. #{nameSpell,jdbcType=VARCHAR},156. #{alias,jdbcType=VARCHAR},157. #{aliasSpell,jdbcType=VARCHAR},158. #{type,jdbcType=INTEGER},159. #{areaId,jdbcType=INTEGER},160. #{cityCode,jdbcType=VARCHAR},161. #{areaCode,jdbcType=VARCHAR},162. #{addr,jdbcType=VARCHAR},163. #{startTime,jdbcType=DATE},164. #{motto,jdbcType=VARCHAR},165. #{webSite,jdbcType=VARCHAR},166. #{phone,jdbcType=VARCHAR},167. #{feature,jdbcType=VARCHAR},168. #{lng,jdbcType=DECIMAL},169. #{lat,jdbcType=DECIMAL},170. #{unitPrice},171. #{salePrice},172. #{natureType,jdbcType=INTEGER},173. #{natureCity,jdbcType=INTEGER},174. #{schoolDegree,jdbcType=INTEGER},175. #{enrolDegree,jdbcType=INTEGER},176. #{imgDegree,jdbcType=INTEGER},177. #{status,jdbcType=TINYINT},178. #{createId,jdbcType=VARCHAR},179. #{createDate,jdbcType=DATE},180. #{updateId,jdbcType=VARCHAR},181. #{updateDate,jdbcType=DATE})182. </insert>183. <insert id="insertSelective" parameterType="mon.entity.school.SchoolInfo"> 184. <selectKey resultType="Integer" keyProperty="id">185. SELECT LAST_INSERT_ID()186. </selectKey>187. INSERT INTO XQ_SCHOOL_INFO188. <trim prefix="(" suffix=")" suffixOverrides=",">189. <if test="name != null">190. NAME,191. </if>192. <if test="nameSpell != null">193. NAME_SPELL,194. </if>195. <if test="alias != null">196. ALIAS,197. </if>198. <if test="aliasSpell != null">199. ALIAS_SPELL,200. </if>201. <if test="type != null">202. TYPE,203. </if>204. <if test="areaId != null">205. AREA_ID,206. </if>207. <if test="cityCode != null">208. CITY_CODE,209. </if>210. <if test="areaCode != null">211. AREA_CODE,212. </if>213. <if test="addr != null">214. ADDR,215. </if>216. <if test="startTime != null">217. START_TIME,218. </if>219. <if test="motto != null">220. MOTTO,221. </if>222. <if test="webSite != null">223. WEB_SITE,224. </if>225. <if test="phone != null">226. PHONE,227. </if>228. <if test="feature != null">229. FEATURE,230. </if>231. <if test="lng != null">232. LNG,233. </if>234. <if test="lat != null">235. LAT,236. </if>237. <if test="UNIT_PRICE != null">238. UNIT_PRICE,239. </if>240. <if test="SALE_PRICE != null ">241. SALE_PRICE,242. </if>243. <if test="natureType != null">244. NATURE_TYPE,245. </if>246. <if test="natureCity != null">247. NATURE_CITY,248. </if>249. <if test="schoolDegree != null">250. SCHOOL_DEGREE,251. </if>252. <if test="enrolDegree != null">253. ENROL_DEGREE,254. </if>255. <if test="imgDegree != null">261. <if test="createId != null">262. CREATE_ID,263. </if>264. <if test="createDate != null">265. CREATE_DATE,266. </if>267. <if test="updateId != null">268. UPDATE_ID,269. </if>270. <if test="updateDate != null">271. UPDATE_DATE,272. </if>273. </trim>274. <trim prefix="VALUES (" suffix=")" suffixOverrides=",">275. <if test="name != null">276. #{name,jdbcType=VARCHAR},277. </if>278. <if test="nameSpell != null">279. #{nameSpell,jdbcType=VARCHAR},280. </if>281. <if test="alias != null">282. #{alias,jdbcType=VARCHAR},283. </if>284. <if test="aliasSpell != null">285. #{aliasSpell,jdbcType=VARCHAR},286. </if>287. <if test="type != null">288. #{type,jdbcType=INTEGER},289. </if>290. <if test="areaId != null">291. #{areaId,jdbcType=INTEGER},292. </if>293. <if test="cityCode != null">294. #{cityCode,jdbcType=VARCHAR},295. </if>296. <if test="areaCode != null">297. #{areaCode,jdbcType=VARCHAR},298. </if>299. <if test="addr != null">300. #{addr,jdbcType=VARCHAR},301. </if>302. <if test="startTime != null">303. #{startTime,jdbcType=DATE},304. </if>305. <if test="motto != null">306. #{motto,jdbcType=VARCHAR},307. </if>308. <if test="webSite != null">309. #{webSite,jdbcType=VARCHAR},310. </if>311. <if test="phone != null">312. #{phone,jdbcType=VARCHAR},313. </if>314. <if test="feature != null">315. #{feature,jdbcType=VARCHAR},316. </if>317. <if test="lng != null">318. #{lng,jdbcType=DECIMAL},319. </if>320. <if test="lat != null">321. #{lat,jdbcType=DECIMAL},322. </if>323. <if test="unitPrice ! =null">324. #{unitPrice},325. </if>326. <if test="salePrice">327. #{salePrice},328. </if>329. <if test="natureType != null">330. #{natureType,jdbcType=INTEGER},331. </if>332. <if test="natureCity != null">333. #{natureCity,jdbcType=INTEGER},334. </if>335. <if test="schoolDegree != null">336. #{schoolDegree,jdbcType=INTEGER},337. </if>338. <if test="enrolDegree != null">339. #{enrolDegree,jdbcType=INTEGER},340. </if>341. <if test="imgDegree != null">342. #{imgDegree,jdbcType=INTEGER},343. </if>344. <if test="status != null">345. #{status,jdbcType=TINYINT},346. </if>347. <if test="createId != null">348. #{createId,jdbcType=VARCHAR},349. </if>350. <if test="createDate != null">351. #{createDate,jdbcType=DATE},352. </if>353. <if test="updateId != null">354. #{updateId,jdbcType=VARCHAR},355. </if>356. <if test="updateDate != null">357. #{updateDate,jdbcType=DATE},358. </if>359. </trim>360. </insert>361. <update id="updateSelective" parameterType="mon.entity.school.SchoolInfo"> 362. UPDATE XQ_SCHOOL_INFO。
黑马程序员:MyBatis的架构设计分析
黑马程序员:MyBatis的架构设计分析MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简单、优雅。
本文主要讲述MyBatis的架构设计思路,并且讨论MyBatis的几个核心部件,来探究MyBatis的实现。
1.接口层---和数据库交互的方式1.1.使用传统的MyBatis提供的API这是传统的传递Statement Id 和查询参数给 SqlSession 对象,使用 SqlSession对象完成和数据库的交互;MyBatis 提供了非常方便和简单的API,供用户实现对数据库的增删改查数据操作,以及对数据库连接信息和MyBatis 自身配置信息的维护操作。
上述使用MyBatis 的方法,是创建一个和数据库打交道的SqlSession对象,然后根据Statement Id 和参数来操作数据库,这种方式固然很简单和实用,但是它不符合面向对象语言的概念和面向接口编程的编程习惯。
由于面向接口的编程是面向对象的大趋势,MyBatis 为了适应这一趋势,增加了第二种使用MyBatis 支持接口(Interface)调用方式。
1.2. 使用Mapper接口MyBatis 将配置文件中的每一个<mapper> 节点抽象为一个 Mapper 接口,而这个接口中声明的方法和跟<mapper> 节点中的<select|update|delete|insert> 节点项对应,即<select|update|delete|insert> 节点的id值为Mapper 接口中的方法名称,parameterType 值表示Mapper 对应方法的入参类型,而resultMap 值则对应了Mapper 接口表示的返回值类型或者返回结果集的元素类型。
根据MyBatis 的配置规范配置好后,通过SqlSession.getMapper(XXXMapper.class) 方法,MyBatis 会根据相应的接口声明的方法信息,通过动态代理机制生成一个Mapper 实例,我们使用Mapper 接口的某一个方法时,MyBatis 会根据这个方法的方法名和参数类型,确定Statement Id,底层还是通过SqlSession.select("statementId",parameterObject);或者SqlSession.update("statementId",parameterObject); 等等来实现对数据库的操作,MyBatis 引用Mapper 接口这种调用方式,纯粹是为了满足面向接口编程的需要。
JAVA MYSQL培训之持久层框架Mybatis学习
MyBatis 映射内部原理-Java反射机制
JAVA反射机制主要提供了以下功能: 1.在运行时判断任意一个对象所属的类 2.在运行时构造任意一个类的对象 3.在运行时判断任意一个类所具有的成员变量和
方法(通过反射甚至可以调用private方法) 4.在运行时调用任意一个对象的方法(*****注意:
MyBatis作为持久层框架,其主要思想是将程 序中的大量sql语句剥离出来,配置在配置文件中, 实现sql的灵活配置。这样做的好处是将sql与程序 代码分离,可以在不修改程序代码的情况下,直 接在配置文件中修改sql。
Mybatis运行原理
Mybatis主要API
sqlSessionFactoryBuilder sqlSessionFactory sqlSession Mapper
SQL实例-insert
SQL实例-insert
SQL实例-delete
SQL实例-update
Sql实例
动态Sql(重点)
动态sql实例-if
动态sql实例-choose,when,otherwise
动态sql实例-where,set
动态sql实例-foreach
注意:你可以传入一个List实例或者一个数组给MyBatis 作为一个参数对象。 如果你这么做,MyBatis 会自动将它包装成一个Map,使用它的名称做为key。List 实例将使用“list” 做为键,数组实例以“array”作为键。
MyBatis基本要素
sql maps:是整个ibatis database layer的核心价值所 在。通过使用sql maps你可以显著的节约数据库操作 的代码量。sql maps使用一个简单的xml文件来实现 从javabean到sql statements的映射。跟其他的框架 或者对象映射工具相比,sql maps最大的优势是简单。
MyBatis源码分析-SQL语句执行的完整流程
MyBatis源码分析-SQL语句执行的完整流程MyBatis 是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。
MyBatis 避免了几乎所有的JDBC 代码和手动设置参数以及获取结果集。
MyBatis 可以对配置和原生Map使用简单的XML 或注解,将接口和Java 的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
如何新建MyBatis源码工程请点击MyBatis源码分析-IDEA新建MyBatis源码工程。
MyBatis框架主要完成的是以下2件事情:根据JDBC规范建立与数据库的连接。
通过反射打通Java对象与数据库参数交互之间相互转换的关系。
MyBatis框架是一种典型的交互式框架,先准备好交互的必要条件,然后构建一个交互的环境,在交互环境中划分会话,在会话中与数据库进行交互数据。
1 MyBatis主要的类Configuration MyBatis所有的配置信息都维持在Configuration对象之中。
SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数,ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换MappedStatement MappedStatement维护了一条<select|update|delete|insert>节点的封装,SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回BoundSql 表示动态生成的SQL语句以及相应的参数信息以上几个类在SQL操作中都会涉及,在SQL操作中重点关注下SQL参数什么时候写入和结果集怎么转换为Java对象,这两个过程正好对应的类是PreparedStatementHandler和ResultSetHandler 类。
手写mybatis 渐进式源码实践
手写mybatis 渐进式源码实践在Java开发中,使用MyBatis作为持久化框架已经是一个比较普遍的选择。
MyBatis提供灵活的SQL编写和映射配置方案,而且易于掌握和使用。
不过,真正理解MyBatis需要去逐步探究其源码实现。
本文将逐步讲述手写MyBatis的全过程,包括从环境搭建、到XML解析、再到Mapper接口调用等流程,希望读者能够深入理解MyBatis的实现原理。
首先,我们需要准备的环境,包括JDK、Maven以及MyBatis源码。
可以通过官网下载MyBatis的源码包,然后解压到本地,使用Maven构建项目。
随后,在项目中添加数据库配置文件,以及Mapper映射文件。
这里以MySQL使用,示例的数据库名为mybatis_test,数据表为user_info,用户信息包括id、name和age等字段。
接下来,我们需要编写基础的Java代码,包括实体类和Mapper接口。
实体类需要实现Serializable接口,且必须与Mapper接口中定义的SQL语句中所涉及到的字段保持一致。
Mapper接口中需要定义相应的CRUD操作方法,并且使用@Param注解指定方法中的参数,以便MyBatis能够正确解析。
例如:public interface UserInfoMapper {UserInfo selectById(@Param("id") Long id);int insert(UserInfo userInfo);int update(UserInfo userInfo);int deleteById(@Param("id") Long id);}接下来,需要编写Mybatis的核心类,SqlSession。
SqlSession主要负责管理Mapper接口的调用过程,以及与数据源的交互。
MyBatis提供了多种SqlSession实现方式,包括DefaultSqlSession、SqlSessionTemplate等。
mybatis中的一二级缓存的实现原理
mybatis中的一二级缓存的实现原理
Mybatis是一款非常流行的Java持久层框架,它采用了缓存机制来提高数据库交互的效率。
其中一级缓存和二级缓存是两种不同的缓存机制,它们都有自己的实现原理。
一级缓存是指在同一个SqlSession中执行相同的SQL语句,返回的结果会被缓存起来。
在同一个SqlSession中,如果执行了相同的SQL语句,Mybatis会先从缓存中查找结果,如果有则直接返回,如果没有则执行SQL语句并将结果缓存。
一级缓存的实现原理是通过一个HashMap来存储结果,其中key为SQL语句,value为结果集。
二级缓存是指在同一个Mapper中执行相同的SQL语句,返回的结果会被缓存起来。
二级缓存是跨SqlSession的,也就是说在不同的SqlSession中执行相同的SQL语句,返回的结果会先从二级缓存中查找。
二级缓存的实现原理是通过一个Cache接口来实现的,该接口有多种实现方式,比如Ehcache、Redis等。
其中,Mybatis默认使用PerpetualCache作为二级缓存的实现方式。
需要注意的是,一级缓存和二级缓存并不是完全相同的,它们有不同的适用场景。
一级缓存适用于单条数据查询,而二级缓存适用于多条数据查询。
此外,在使用二级缓存时需要注意缓存的有效期,避免出现脏数据问题。
总之, Mybatis的缓存机制是通过一级缓存和二级缓存来提高数据库交互效率的。
对于开发者来说,需要根据业务需求选择合适的缓存机制,避免出现性能问题。
mybatis的原理
mybatis的原理MyBatis是一个开源的持久层框架,它支持定制化SQL、存储过程以及高级映射。
MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。
MyBatis使用简单的XML或注解来配置和映射原始类型、接口和Java的POJO (Plain Old Java Objects)为数据库中的记录。
MyBatis的原理可以概括为以下几个方面:1. SQL映射配置,MyBatis通过XML或注解来配置SQL映射,将Java方法和SQL语句进行映射关联。
在XML中,我们可以定义select、insert、update和delete等操作,以及参数映射、结果映射等。
2. SQL会话管理,MyBatis通过SqlSessionFactoryBuilder和SqlSessionFactory来构建SqlSession,SqlSession是执行持久化操作的关键对象,它包含了执行SQL所需的所有方法。
SqlSession的生命周期应该被限制在一个方法的范围内,它不是线程安全的,因此每次执行持久化操作时都应该打开一个新的SqlSession,执行完毕后及时关闭。
3. 参数映射,MyBatis支持多种参数映射方式,包括基本类型、Map、POJO等。
在SQL语句中,我们可以通过#{}或${}来引用参数,#{}会将参数设置为预编译参数,${}会将参数直接拼接到SQL语句中。
4. 结果映射,MyBatis支持将查询结果映射为Java对象或集合,通过配置resultMap可以定义查询结果和Java对象之间的映射关系。
MyBatis还支持延迟加载、嵌套查询等高级结果映射功能。
5. 插件扩展,MyBatis提供了插件机制,可以通过插件来扩展MyBatis的功能,比如实现SQL拦截、结果集处理等。
MyBatis的工作原理可以简单概括为,首先,通过SqlSessionFactoryBuilder构建SqlSessionFactory,然后通过SqlSessionFactory打开一个SqlSession,最后通过SqlSession执行SQL语句并处理结果。
Java持久化框架:MyBatis和JPA
Java持久化框架:MyBatis和JPA引言在Java开发领域,持久化是一个非常重要的概念。
它指的是将数据存储到数据库中,以便在程序重新运行时能够恢复数据。
为了实现持久化,开发人员通常使用一种持久化框架来简化数据库操作。
本文将重点介绍两个流行的Java持久化框架:MyBatis和JPA。
1. MyBatisMyBatis是一个开源的持久化框架,它通过将SQL语句和Java代码进行映射,从而实现数据库操作的简化。
MyBatis的核心思想是将SQL语句与Java代码分离,使得开发人员能够更灵活地对数据库进行操作。
1.1 映射文件在MyBatis中,开发人员需要编写映射文件来定义SQL语句与Java代码之间的映射关系。
映射文件通常包含SQL语句、参数映射和结果映射等信息。
通过使用映射文件,开发人员可以实现灵活的数据库操作。
1.2 SQL语句的执行MyBatis提供了丰富的API来执行SQL语句。
开发人员可以通过SqlSessionFactory创建SqlSession对象,然后使用SqlSession对象执行SQL 语句。
SqlSession提供了诸如insert、update、delete和select等方法来执行不同类型的SQL语句。
1.3 动态SQLMyBatis支持动态SQL,开发人员可以根据不同的条件生成不同的SQL语句。
通过使用动态SQL,开发人员可以实现更灵活的数据库操作。
1.4 缓存MyBatis支持缓存机制,可以提高数据库访问的性能。
MyBatis提供了一级缓存和二级缓存两种类型的缓存。
一级缓存是指SqlSession级别的缓存,而二级缓存是指SqlSessionFactory级别的缓存。
2. JPAJPA是Java持久化API的缩写,它是一种Java规范,旨在简化数据库操作。
JPA 提供了一系列的API和注解,使得开发人员能够更加方便地进行数据库操作。
2.1 实体类在JPA中,开发人员需要定义实体类来映射数据库中的表。
MyBatis框架介绍以及快速入门
MyBatis框架介绍以及快速⼊门MyBatis框架今⽇学习内容⽬标能够了解什么是框架理解⾃定义Mybatis框架掌握Mybatis框架开发快速⼊门第⼀节认识框架1.介绍框架就是⼀个架⼦,表演节⽬,舞台已经搭建好,表演什么节⽬,看⾃⼰的需求了。
框架是⼀个半成品,对于Java语⾔来说,框架就是封装了别⼈的代码。
在框架的基础上我们在进⼀步开发,拿来⽤。
2.解决的问题解决的是技术整合问题。
软件开发环境和规模都很⼤,不可能任何⼀个项⽬的代码都从零开始,此时就需要⼀个⾮常优秀的框架把基础技术整合完毕,我们在他的基础上进⼀步开发。
提⾼性能,易扩展,易维护,最终提⾼整个团队的开发效率。
3.使⽤框架企业级⼤型项⽬开发⽤框架,避免⼤炮打蚊⼦。
Java的框架是具有⼀些共性导⼊jar包框架运⾏细节定义,也就是编写配置⽂件(xml)调⽤框架中的api第⼆节原⽣JDBC案例查询user表以List集合形式返回编写pojo类(User)domain,pojo本质都是相同的1.JdbcDemo类/*** 原始的JDBC,对数据表user查询,结果集存储List集合* */public class JdbcDemo {public static void main(String[] args) throws Exception {// 注册驱动Class.forName("com.mysql.jdbc.Driver");// 获取连接Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis","root","root");// SQL语句执⾏对象PreparedStatement pst = con.prepareStatement("select * from user");// 执⾏查询,返回结果集ResultSet rs = pst.executeQuery();List<User> userList = new ArrayList<User>();while (rs.next()){User user = new User();// 取出表中数据,rs对象的⽅法getXXX()user.setId(rs.getInt("id"));user.setUsername(rs.getString("username"));user.setSex(rs.getString("sex"));user.setBirthday(rs.getDate("birthday"));user.setAddress(rs.getString("address"));userList.add(user);}for (User user : userList){System.out.println(user);}rs.close();pst.close();con.close();}}er类// 和数据库中的键对照public class User {private int id;private String username;private String sex;private Date birthday;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) {ername = username;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", sex='" + sex + '\'' +", birthday=" + birthday +", address='" + address + '\'' +'}';}}3.原始的JDBC的缺陷原始程序问题:维护性差,扩展性差,出现问题,修改源码,代码量⼤1. 频繁连接,释放数据库资源,降低系统性能解决办法:连接池2. 数据库驱动类,连接四⼤信息解决办法:写配置⽂件,读取3. SQL语句硬编码,SQL语句写死了 SQL语句中的?占位符解决办法:写配置⽂件,读取4. 封装数据表结果集代码,硬编码引出连接池,Apache DBUtils4.框架框架:最基本的代码,整合起来连接数据库,执⾏SQL语句,封装结果集整合只要提供:SQL语句,写xml中第三节 MyBatis框架1.历史Mybatis原本是Apache软件基⾦会的⼀个开源项⽬叫做iBatis,2010年这个项⽬由Apache迁移到了google code管理才改名为Mybatis,2013年⼜迁移到了GitHub。
mybatis源码分析(一)框架结构概览
mybatis源码分析(⼀)框架结构概览本篇博客将主要对 mybatis 整体介绍,包括 mybatis 的项⽬结构,执⾏的主要流程,初始化流程,API 等各模块进⾏简单的串联,让你能够对mybatis 有⼀个整体的把握。
另外在 mybatis 源码的阅读过程中,如果不想写 demo 可以直接使⽤项⽬中的单元测试;⼀、mybatis 结构介绍mybatis的主要功能和使⽤ demo,在⽹上已经有很多了我就不再啰嗦了,同时也⾮常的详细;另外 mybatis 中使⽤了多种设计模式,包括建造者、动态代理、策略、装饰器模式等,在查看源码的时候,最好先对这些设计模式有⼀定的了解;其中 mybatis 的模块结构如下:mybatis 的执⾏流程如下:⾸先通过 Java API 或者 XML 配置完成初始化,最终所有的配置都在 Configuration 类中维护;然后通过 SqlSessionFactory 得到 SqlSession,这⾥ SqlSession 就是 mybatis 的顶层 API 了,主要通过他完成数据库的增删改查等操作;然后 SqlSession 将具体的操作委托给 Executor 执⾏,Executor 就是 mybatis 的调度核⼼了,主要职责有 SQL 语句⽣成、⼀⼆级缓存维护和事务的相关操作;然后 Executor 将数据库相关的操作委托给 StatementHandler,StatementHandler 中完成了 mybatis 最核⼼的⼯作,包括参数绑定,指定 SQL 语句,结果集映射等;具体过程如图所⽰:⼆、初始化mybatis 中包含了很多的配置项,具体每⼀项的讲解也很详细,其结构⼤致如下:(另外正如上⾯说的 mybatis 的配置项最后都由 Configuration 类维护,这其实就是外观模式)configuration(配置)properties(属性)settings(设置)typeAliases(类型别名)typeHandlers(类型处理器)objectFactory(对象⼯⼚)plugins(插件)environments(环境配置)environment(环境变量)transactionManager(事务管理器)dataSource(数据源)mappers(映射器)1. Java API 初始化Java API 初始化的⽅式虽然不常⽤,但是相较于 XML 的⽅式可以更清楚的看到 Configuration 的构成,其⽰例如下:PooledDataSource dataSource = new PooledDataSource();dataSource.setDriver("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT");dataSource.setUsername("root");dataSource.setPassword("root");TransactionFactory transactionFactory = new JdbcTransactionFactory();Environment environment = new Environment("development", transactionFactory, dataSource);Configuration configuration = new Configuration(environment);configuration.addMapper(UserMapper.class);sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);2. XML 配置初始化相交于 Java API 的⽅式,XML 配置初始化,必然会多出 XML 的解析部分;代码如下:String resource = "org/apache/ibatis/builder/MapperConfig.xml";Reader reader = Resources.getResourceAsReader(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);SqlSession sqlSession = sqlSessionFactory.openSession();下⾯是⼀个相对完整的配置⽰例:<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-////DTD Config 3.0//EN" "/dtd/mybatis-3-config.dtd"><configuration><properties resource="org/apache/ibatis/databases/blog/blog-derby.properties"/><settings><setting name="cacheEnabled" value="true"/><setting name="lazyLoadingEnabled" value="false"/>...</settings><typeAliases><typeAlias alias="Author" type="org.apache.ibatis.domain.blog.Author"/><typeAlias alias="Blog" type="org.apache.ibatis.domain.blog.Blog"/>...</typeAliases><typeHandlers><typeHandler javaType="String" jdbcType="VARCHAR" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/></typeHandlers><objectFactory type="org.apache.ibatis.builder.ExampleObjectFactory"><property name="objectFactoryProperty" value="100"/></objectFactory><plugins><plugin interceptor="org.apache.ibatis.builder.ExamplePlugin"><property name="pluginProperty" value="100"/></plugin></plugins><environments default="development"><environment id="development"><transactionManager type="JDBC"><property name="" value=""/></transactionManager><!--<dataSource type="UNPOOLED">--><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><mappers><mapper resource="org/apache/ibatis/builder/AuthorMapper.xml"/><mapper resource="org/apache/ibatis/builder/BlogMapper.xml"/>...</mappers></configuration>其解析的流程如下:主要代码如下:public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try {XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);return build(parser.parse());} catch (Exception e) {throw ExceptionFactory.wrapException("Error building SqlSession.", e);} finally {ErrorContext.instance().reset();try {inputStream.close();} catch (IOException e) { }}}public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);}从上⾯的代码和流程图中可以看到,XML 初始化的主要流程被封装到了 XMLConfigBuilder 当中;主要的代码逻辑如下:public Configuration parse() {if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); }parsed = true;parseConfiguration(parser.evalNode("/configuration"));return configuration;}private void parseConfiguration(XNode root) {try {//issue #117 read properties firstpropertiesElement(root.evalNode("properties"));Properties settings = settingsAsProperties(root.evalNode("settings"));loadCustomVfs(settings);loadCustomLogImpl(settings);typeAliasesElement(root.evalNode("typeAliases"));pluginElement(root.evalNode("plugins"));objectFactoryElement(root.evalNode("objectFactory"));objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));reflectorFactoryElement(root.evalNode("reflectorFactory"));settingsElement(settings);// read it after objectFactory and objectWrapperFactory issue #631environmentsElement(root.evalNode("environments"));databaseIdProviderElement(root.evalNode("databaseIdProvider"));typeHandlerElement(root.evalNode("typeHandlers"));mapperElement(root.evalNode("mappers"));} catch (Exception e) {throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);}}三、SqlSession 使⽤⽅式1. 直接指定 MappedStatementtry (SqlSession session = sqlMapper.openSession()) {Author author = session.selectOne("org.apache.ibatis.domain.blog.mappers.AuthorMapper.selectAuthor", new Author(101));}这种⽅式通过 namespace + sqlId 的⽅式直接指定 MappedStatement;这种⽅式因为直接编写字符串和强类型转换,既不安全也稍显⿇烦,所以现在已经不推荐使⽤了;@Overridepublic <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {try {MappedStatement ms = configuration.getMappedStatement(statement);Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);registerCursor(cursor);return cursor;} catch (Exception e) {throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);} finally {ErrorContext.instance().reset();}}2. 动态代理 Mapper 的⽅式try (SqlSession session = sqlMapper.openSession()) {AuthorMapper mapper = session.getMapper(AuthorMapper.class);Author author = mapper.selectAuthor(500);}这种⽅式不经避免了以上的问题,同时也能够使⽤注解的⽅式编写 sql,⽽且可以使⽤ IDE 提⽰;现在⼀般都推荐使⽤这种⽅式;但是其最终也是调⽤了上⾯的接⼝;⾸先在初始化的时候通过 bindMapperForNamespace,注册对应的 Mapper(要求namespace和Mapper的全限定名保持⼀致);// XMLMapperBuilderprivate void bindMapperForNamespace() {String namespace = builderAssistant.getCurrentNamespace();if (namespace != null) {Class<?> boundType = null;try {boundType = Resources.classForName(namespace);} catch (ClassNotFoundException e) { //ignore, bound type is not required }if (boundType != null) {if (!configuration.hasMapper(boundType)) {configuration.addLoadedResource("namespace:" + namespace);configuration.addMapper(boundType);}}}}// MapperRegistrypublic <T> void addMapper(Class<T> type) {if (type.isInterface()) {if (hasMapper(type)) { throw new BindingException("Type " + type + " is already known to the MapperRegistry."); }boolean loadCompleted = false;try {knownMappers.put(type, new MapperProxyFactory<>(type)); // 添加代理⼯⼚MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);parser.parse();loadCompleted = true;} finally {if (!loadCompleted) {knownMappers.remove(type);}}}}使⽤的时候,通过 class 类名获取 MapperProxyFactory 代理⼯⼚,制造⼀个新的 Mapper 代理(注意这⾥时每次都要⽣成⼀个代理类,因为其中包含了 SqlSession,⽽ SqlSession 是线程不安全的所以不能缓存,但是我觉得这⾥任然是可以优化的,有兴趣你可以⾃⼰尝试⼀下);try (SqlSession session = sqlMapper.openSession()) {AuthorMapper mapper = session.getMapper(AuthorMapper.class); // 代理类}// MapperRegistrypublic <T> T getMapper(Class<T> type, SqlSession sqlSession) {final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); }try {return mapperProxyFactory.newInstance(sqlSession); // 创建代理对象} catch (Exception e) {throw new BindingException("Error getting mapper instance. Cause: " + e, e);}}// MapperProxyFactorypublic T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy);}// MapperProxypublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (Object.class.equals(method.getDeclaringClass())) { // 从Object中继承的⽅法return method.invoke(this, args);} else if (method.isDefault()) { // 有默认实现的接⼝⽅法return invokeDefaultMethod(proxy, method, args);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}final MapperMethod mapperMethod = cachedMapperMethod(method);return mapperMethod.execute(sqlSession, args); // 然后由 MapperMethod 执⾏,这⾥使⽤策略模式,后⾯还会详细讲解}总结SqlSession 是线程不安全的,所以在⽰例代码中每次使⽤都会将其关闭?在 mybatis 中还有⼀个类 SqlSessionManager ⾥⾯有⼀个 ThreadLocal ⽤来管理 SqlSession,在 Spring 中也同样是⽤ SqlSessionHolder 来管理的,所以并不会每次都创建⼀个新的 SqlSession;以上内容只是⼤致将了 mybatis 的主要结构,后⾯的章节还会分模块进⾏讲解;另外本⽂主要参考了《MyBatis技术内幕》,有兴趣的可以⾃⾏查看;。
手把手带你阅读Mybatis源码(一)构造篇
⼿把⼿带你阅读Mybatis源码(⼀)构造篇前⾔今天会给⼤家分享我们常⽤的持久层框架——MyBatis的⼯作原理和源码解析,后续会围绕Mybatis框架做⼀些⽐较深⼊的讲解,之后这部分内容会归置到公众号菜单栏:连载中…-框架分析中,欢迎探讨!说实话MyBatis是我第⼀个接触的持久层框架,在这之前我也没有⽤过Hibernate,从Java原⽣的Jdbc操作数据库之后就直接过渡到了这个框架上,当时给我的第⼀感觉是,有⼀个框架太⽅便了。
举⼀个例⼦吧,我们在Jdbc操作的时候,对于对象的封装,我们是需要通过ResultSet.getXXX(index)来获取值,然后在通过对象的setXXX()⽅法进⾏⼿动注⼊,这种重复且⽆任何技术含量的⼯作⼀直以来都是被我们程序猿所鄙视的⼀环,⽽MyBatis就可以直接将我们的SQL查询出来的数据与对象直接进⾏映射然后直接返回⼀个封装完成的对象,这节省了程序猿⼤部分的时间,当然其实JdbcTemplate也可以做到,但是这⾥先不说。
MyBatis的优点有⾮常多,当然这也只有同时使⽤过Jdbc和MyBatis之后,产⽣对⽐,才会有这种巨⼤的落差感,但这并不是今天要讨论的重点,今天的重⼼还是放在MyBatis是如何做到这些的。
对于MyBatis,给我个⼈的感受,其⼯作流程实际上分为两部分:第⼀,构建,也就是解析我们写的xml配置,将其变成它所需要的对象。
第⼆,就是执⾏,在构建完成的基础上,去执⾏我们的SQL,完成与Jdbc的交互。
⽽这篇的重点会先放在构建上。
Xml配置⽂件玩过这个框架的同学都知道,我们在单独使⽤它的时候,会需要两个配置⽂件,分别是mybatis-config.xml和mapper.xml,在官⽹上可以直接看到,当然这⾥为了⽅便,我就直接将我的xml配置复制⼀份。
<!-- mybatis-config.xml --><?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-////DTD Config 3.0//EN""/dtd/mybatis-3-config.dtd"><configuration><!-- 和spring整合后 environments配置将废除 --><environments default="development"><environment id="development"><!-- 使⽤jdbc事务管理 --><transactionManager type="JDBC" /><!-- 数据库连接池 --><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver" /><property name="url"value="jdbc:mysql://xxxxxxx:3306/test?characterEncoding=utf8"/><property name="username" value="username" /><property name="password" value="password" /></dataSource></environment></environments><!-- 加载mapper.xml --><mappers><!-- <package name=""> --><mapper resource="mapper/DemoMapper.xml" ></mapper></mappers></configuration><!-- DemoMapper.xml --><?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN" "/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.DemoMapper"><select id="queryTest" parameterType="Map" resultType="Map">select * from test WHERE id =#{id}</select></mapper>我们不难看出,在mybatis-config.xml这个⽂件主要是⽤于配置数据源、配置别名、加载mapper.xml,并且我们可以看到这个⽂件的<mappers>节点中包含了⼀个<mapper>,⽽这个mapper所指向的路径就是另外⼀个xml⽂件:DemoMapper.xml,⽽这个⽂件中写了我们查询数据库所⽤的SQL。
ssm框架之持久层mybatis动态sql标签属性大全
ssm框架之持久层mybatis动态sql标签属性⼤全1. 定义sql语句1.1 select 标签id :唯⼀的标识符.parameterType:传给此语句的参数的全路径名或别名例:er或userresultType :语句返回值类型或别名。
注意,如果是集合,那么这⾥填写的是集合的泛型,⽽不是集合本⾝(resultType 与resultMap 不能并⽤)<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="Object">select * from student where id=#{id}</select>1.2 insert标签属性介绍:id :唯⼀的标识符parameterType:传给此语句的参数的全路径名或别名例:er<insert id="insert" parameterType="Object">insert into student <trim prefix="(" suffix=")" suffixOverrides="," ><if test="name != null "> NAME, </if></trim> <trim prefix="values(" suffix=")" suffixOverrides="," ><if test="name != null "> #{name}, </if></trim></insert>1.3 delete标签属性同 insert<delete id="deleteByPrimaryKey" parameterType="Object">delete from student where id=#{id}</delete>1.4 update标签属性同 insert2. 配置JAVA对象属性与查询结果集中列名对应关系resultMap 标签的使⽤基本作⽤:建⽴SQL查询结果字段与实体属性的映射关系信息查询的结果集转换为java对象,⽅便进⼀步操作。
Mybatis一二级缓存的使用和实现原理
Mybatis一二级缓存的使用和实现原理概述针对查询操作,mybatis支持通过缓存的方式来减少SQL的调用,提高查询性能。
在缓存级别方面分为一级缓存和二级缓存,1. 一级缓存的粒度较小,是与某个SqlSession绑定的,只对该SqlSession的相关查询操作进行缓存,不同SqlSession实例之间相互不影响,缓存为使用本地内存实现;2. 二级缓存是一种全局缓存,是由所有SqlSession实例所共享的,即不同SqlSession实例查询时产生的缓存,对其他SqlSession实例可见。
一级缓存l mybatis的一级缓存支持两种缓存级别,分别是SESSION和STATEMENT,默认的一级缓存级别为SESSION。
l mybatis的一级缓存是默认开启的。
l 一级缓存的使用示意图如下:(图片引用自:mybatis一级缓存二级缓存)SESSION级别l 对该SqlSession实例发起的查询操作进行缓存,即由同一SqlSession实例发起的多次相同(SQL和SQL的参数值都相同)的查询操作,第一次是查询数据库,后续则查询缓存;但是如果另外一个SqlSession实例进行相同的查询操作,则需要进行数据库查询。
l 针对更新操作,如果是该SqlSession自身进行了更新操作,则该SqlSession对应的一级缓存会被清空,但是如果是其他SqlSession 实例进行了更新操作,则此更新操作对该SqlSession不可见,所以该SqlSession的缓存数据是过期失效数据,所以SqlSession实例的生命周期不能过长,否则可能出现数据不一致现象。
STATEMENT级别l 该级别是指缓存只针对当前执行的查询语句有效,故每次语句执行完之后都会清空缓存,其实是相当于没有缓存,即该sqlSession 实例下次调用相同的SQL语句和相同参数值时,由于上一次语句执行后,缓存被清空了,故需要继续查询数据库。
手写mybatis渐进式源码实践
手写mybatis渐进式源码实践在Java开发中,ORM框架已经成为了必不可少的工具之一。
MyBatis就是其中的佼佼者。
要想更加深入了解MyBatis的工作原理,最好的方式就是去实现一个简单的MyBatis。
在这篇文章中,我会介绍如何手写一个简易版MyBatis。
步骤1:编写常量类在编写MyBatis之前,我们需要先定义一些常量,这样可以防止代码中出现魔法值。
比如:```public class Constants {public static final String JDBC_DRIVER_CLASS ="jdbc.driverClass";public static final String JDBC_URL = "jdbc.url";public static final String JDBC_USERNAME ="ername";public static final String JDBC_PASSWORD ="jdbc.password";}```步骤2:定义配置对象在MyBatis中,最重要的就是配置。
我们需要定义一个配置对象来存储配置信息。
例如:```public class Configuration {private String jdbcDriverClass;private String jdbcUrl;private String jdbcUsername;private String jdbcPassword;private Map<String, String> mappers = new HashMap<>();// 省略getter和setter}```这里的mappers属性是用来存储Mapper接口路径和Mapper XML 文件的映射关系的。
步骤3:解析XML配置文件MyBatis中的Mapper接口通常都是定义在XML文件中的,因此我们需要解析XML文件,把里面的SQL语句和配置信息提取出来。