永久免费自助建站系统,海外注册域名的网站,网站 建设公司,沈阳亚洲城属于哪个社区MyBatis
定义
它是一款半自动的ORM持久层框架#xff0c;具有较高的SQL灵活性#xff0c;支持高级映射(一对一#xff0c;一对多)#xff0c;动态SQL#xff0c;延迟加载和缓存等特性#xff0c;但它的数据库无关性较低
**ORM: **Object Relation Mapping#xff0c;…MyBatis
定义
它是一款半自动的ORM持久层框架具有较高的SQL灵活性支持高级映射(一对一一对多)动态SQL延迟加载和缓存等特性但它的数据库无关性较低
**ORM: **Object Relation Mapping对象关系映射。对象指的是Java对象关系指的是数据库中的关系模型对象关系映射指的就是在Java对象和数据库的关系模型之间建立一种对应关系比如用一个Java的Student类去对应数据库中的一张student表类中的属性和表中的列一一对应。Student类就对应student表一个Student对象就对应student表中的一行数据
半自动: 用mybatis进行开发需要手动编写SQL语句。而全自动的ORM框架如hibernate则不需要编写SQL语句。
优点 灵活性高,自由地对sql进行定制 但相比JDBC它提供了输入映射和输出映射可以很方便地进行SQL参数设置以及结果集封装。 还提供了关联查询和动态SQL等功能极大地提升了开发的效率。
缺点
当要切换数据库时SQL语句可能就要重写因为不同的数据库有不同的方言(Dialect)所以mybatis的数据库无关性低。
占位符
#{}
#{}在mybatis中最后会被解析为?其实就是Jdbc的PreparedStatement中的?占位符它有预编译的过程预编译 它有预编译的过程会对输入参数进行类型解析(如果入参是String类型设置参数时会自动加上引号)可以防止SQL注入 注意 如果parameterType属性指定的入参类型是简单类型的话(简单类型指的是8种java原始类型再加一个String)#{}中的变量名可以任意如果入参类型是pojo比如是Student类,那么#{name}表示取入参对象Student中的name属性#{age}表示取age属性
${}
${}一般会用在模糊查询的情景比如SELECT * FROM student WHERE name like %${name}%;处理阶段在#{}之前它不会做参数类型解析而仅仅是做了字符串的拼接入参的Student对象的name属性为zhangsan则上面那条SQL最终被解析为SELECT * FROM student WHERE name like ‘%zhangsan%’;模糊查询只能用${}对于简单类型(8种java原始类型再加一个String)的入参${}中参数的名字必须是value
使用过程
原生流程
编写mapper.xml书写SQL并定义好SQL的输入参数和输出参数编写全局配置文件配置数据源以及要加载的mapper.xml文件通过全局配置文件创建SqlSessionFactory每次进行CRUD时通过SqlSessionFactory创建一个SqlSession调用SqlSession上的selectOneselectListinsertdeleteupdate等方法传入mapper.xml中SQL标签的id以及输入参数提交sqlSession.commit()关闭资源sqlSession.close()
基于Mapper代理
为了简化开发mybatis提供了mapper接口代理的开发方式不需要再编写dao类只需要编写一个mapper接口一个mapper的接口和一个mapper.xml相对应只需要调用SqlSession对象上的getMapper()传入mapper接口的class信息即可获得一个mapper代理对象直接调用mapper接口中的方法即相当于调用mapper.xml中的各个SQL标签此时就不需要指定SQL标签的id字符串了mapper接口中的一个方法就对应了mapper.xml中的一个SQL标签
注意
mapper接口的全限定名要和mapper.xml的namespace属性一致mapper接口中的方法名要和mapper.xml中的SQL标签的id一致mapper接口中的方法入参类型要和mapper.xml中SQL语句的入参类型一致mapper接口中的方法出参类型要和mapper.xml中SQL语句的返回值类型一致
使用方法
全局配置文件
!-- 普通加载xml --
mappers mapper resourceStudentMapper.xml/
/mappersmapper.java mapper.xml 测试调用 基于注解的开发
还是得有一个全局配置的xml文件不过mapper.xml就可以省掉了
注意
当使用注解开发时若需要传入多个参数可以结合Param注解 Param标签会被mybatis处理并封装成一个Map对象比如上面的示例中实际传入的参数是一个Map对象Param标签帮忙向Map中设置了值即它做了 MapString,Object map new HashMap(); map.put(name, name);
map.put(major,major);步骤
创建一个Mapper接口
!-- 在mapper接口中使用注解 --
mappers mapper classcom.yogurt.mapper.PureStudentMapper/
/mappers在全局配置文件中修改标签直接指定加载这个类
三种加载Mapper的方式 !-- 普通加载xml --
mappersmapper resourceStudentMapper.xml/
/mappers!-- 在mapper接口中使用注解 --
mappersmapper classcom.yogurt.mapper.PureStudentMapper/
/mappers!-- 使用package标签 --
mapperspackage namecom.yogurt.mapper/
/mappers自动加载com.yogurt.mapper包下的所有mapper这种方式需要将mapper接口文件和mapper.xml文件都放在com.yogurt.mapper包下且接口文件和xml文件的文件名要一致。若mapper接口采用注解方式则不需要xml;若mapper接口没有采用注解方式则mapper接口和xml文件的名称要相同且在同一目录 注意 是因为对于src/main/java 源码目录下的文件maven打包时只会将该目录下的java文件打包而其他类型的文件都不会被打包进去去工程目录的target目录下看看maven构建后生成的文件 解决 需要在pom.xml中的 标签下 添加 标签指定打包时要将xml文件打包进去 buildresourcesresourcedirectorysrc/main/java/directoryincludesinclude**/*.xml/include/includes/resource/resources
/build运行流程
流程
利用Xpath语法解析全局配置文件解析全局配置 是否开启二级缓存是否开启延迟加载是否使用插件plugin是否设置类型别名typeAlias数据库连接信息 解析mapper映射文件将每个CRUD标签封装为一个MappedStatement所有的信息封装到Configuration对象这是一个重量级对象将Configuration封装到SqlSessionFactory中每次调用SqlSessionFactory开启一个SqlSession每个SqlSession会持有一个私有的Executor对象以及共享的Configuration对象每次操作选取一个MappedStatement由Executor执行。包括SQL语句组装参数解析返回结果解析等操作
图示 关键类 Configuration 封装了所有的属性 MappedStatement 一个CRUD标签对应一个MappedStatement Executor体系 mybatis核心执行器通过Executor来执行数据库操作 SqlSource体系 封装CRUD标签的一个SqlSource用于组装SQL语句 SqlNode体系 以树状形式存储动态SQL标签一个SqlSource拥有一个rootSqlNode每个SqlNode有一个apply方法在Executor执行时用于拼接SQL语句SqlNode的设计用到的是设计模式中的组合模式。 StatementHandler 生成Statement设置参数执行查询 ParameterHandler 设置参数时进行参数解析类型转换等 ResultSetHandler 获取结果集并进行结果封装
MyBatis缓存
定义
mybatis缓存将数据库的查询结果保存到内存或者硬盘以便下次执行相同查询时不经过数据库直接从内存中取出结果
作用
对于重复的查询它能够提高响应速度并减轻数据库的访问压力。适用于对响应时间要求高而数据实时性要求不高的情况下。
分类
一级缓存
作用范围
SqlSession默认
持有者
BaseExecutor
默认开启
其实是无法关闭的但可以通过一些方法来使一级缓存失效
清除缓存
在同一个SqlSession里执行 增 删 改 操作时不必提交会清除一级缓存SqlSession提交或关闭时关闭时会自动提交会清除一级缓存对mapper.xml中的某个CRUD标签设置属性flushCachetrue 这样会导致该标签的一级缓存和二级缓存都失效在全局配置文件中设置 这样会使一级缓存失效二级缓存不受影响
二级缓存
作用范围
mapper级别(可以跨SqlSession)一个mapper.xml即对应一个二级缓存每个二级缓存以mapper文件的namespace作为唯一标识
持有者
MappedStatement
默认关闭
其实全局配置文件中的cacheEnabled默认是true这个是二级缓存总开关默认是已经打开了的然而必须要在mapper.xml中配置 标签才能开启该mapper.xml的二级缓存
开启效果
映射语句文件中的所有SELECT 语句将会被缓存。映射语句文件中的所有时INSERT 、UPDATE 、DELETE 语句会刷新缓存。缓存会使用Least Rece ntly U sed ( LRU 最近最少使用的算法来收回。根据时间表如no Flush Int erv al 没有刷新间隔缓存不会以任何时间顺序来刷新。缓存会存储集合或对象无论查询方法返回什么类型的值的1024 个引用。缓存会被视为read/write可读可写的意味着对象检索不是共享的而且可以安全地被调用者修改而不干扰其他调用者或线程所做的潜在修改。
注意
对于SELECT节点对应的MappedStatement默认是开启二级缓存对其他节点INSERT/DELETE/UPDATE默认是关闭这是由MappedStatement里的useCache属性控制的放入二级缓存的数据默认要实现Serializable接口因为二级缓存的存储介质除了内存还可能存在硬盘所以存储的对象需要可序列化。 readOnlyfalse通过序列化返回缓存对象的一份拷贝速度上会慢一些但是更加安全。用户取得数据后执行修改并不会影响到二级缓存中的对象这些对象可以随意修改不会影响后续相同查询条件的结果。这会慢一些但是安全因此默认是false。 当然若把二级缓存的readOnly属性设为true则对象数据可以不用实现Serializable接口 readOnlytrue返回缓存对象的引用。因此返回的这些缓存对象自己没事不要去修改。一旦修改就会影响下一个相同查询条件的查询结果。这提供了很重要的性能优势。readOnlytrue意在告诉用户从缓存中取出数据后不要对数据进行修改而不是保证缓存的只读性cache中存的是对象引用取出数据后若执行修改则会改变真正的对象另外的用户再从cache中取对象则会发现对象已经被修改 执行一次查询后需要进行提交该次查询结果才会保存到二级缓存中
存在问题
由于是每个namespace对应一个二级缓存一个namespace就是一个mapper.xml若mapperA.xml中全是对user表的操作而在另一个mapperB.xml中也有少许对user表的操作这2个mapper的二级缓存是互相独立的然而mapperB若对user表执行了增删改并提交却不会刷新到mapperA的二级缓存此时用mapperA去做查询则可能取到脏数据。
应用场景
主键返回
在插入一条记录时我们不设置其主键id而让数据库自动生成该条记录的主键id那么在插入一条记录后如何得到数据库自动生成的这条记录的主键id呢
两种方式
使用useGeneratedKeys和keyProperty属性
insert idinsert parameterTypecom.yogurt.po.Student useGeneratedKeystrue keyPropertyidINSERT INTO student (name,score,age,gender) VALUES (#{name},#{score},#{age},#{gender});
/insert使用子标签
insert idinsert parameterTypecom.yogurt.po.StudentINSERT INTO student (name,score,age,gender) VALUES (#{name},#{score},#{age},#{gender});selectKey keyPropertyid orderAFTER resultTypeint SELECT LAST_INSERT_ID();/selectKey
/insert标签其实就是一条SQL这条SQL的执行可以放在主SQL执行之前或之后并且会将其执行得到的结果封装到入参的Java对象的指定属性上。
注意子标签只能用在和标签中。上面的LAST_INSERT_ID()实际上是MySQL提供的一个函数可以用来获取最近插入或更新的记录的主键id。
批量查询
主要是动态SQL标签的使用注意如果parameterType是List的话则在标签体内引用这个List只能用变量名list如果parameterType是数组则只能用变量名array
mapper定义
select idbatchFind resultTypestudent parameterTypejava.util.ListSELECT * FROM studentwhereif testlist ! null and list.size() 0AND id inforeach collectionlist itemid open( separator, close)#{id}/foreach/if/where
/select传参
ListStudent students mapper.batchFind(Arrays.asList(1, 2, 3, 7, 9));动态sql
可以根据具体的参数条件来对SQL语句进行动态拼接。
注意
由于不确定查询参数是否存在许多人会使用类似于where 1 1 来作为前缀然后后面用AND 拼接要查询的参数这样就算要查询的参数为空也能够正确执行查询如果不加1 1则如果查询参数为空SQL语句就会变成SELECT * FROM student where SQL不合法。
if
select idfind resultTypestudent parameterTypestudentSELECT * FROM student WHERE age 18if testname ! null and name ! AND name like %${name}%/if
/selectchoose
select idfindActiveBlogLikeresultTypeBlogSELECT * FROM BLOG WHERE state ‘ACTIVE’choosewhen testtitle ! nullAND title like #{title}/whenwhen testauthor ! null and author.name ! nullAND author_name like #{author.name}/whenotherwiseAND featured 1/otherwise/choose
/select where 标签只会在至少有一个子元素返回了SQL语句时才会向SQL语句中添加WHERE并且如果WHERE之后是以AND或OR开头会自动将其删掉
select idfindActiveBlogLikeresultTypeBlogSELECT * FROM BLOGwhereif teststate ! nullstate #{state}/ifif testtitle ! nullAND title like #{title}/ifif testauthor ! null and author.name ! nullAND author_name like #{author.name}/if/where
/selecttrim 标签可以用标签代替
trim prefixWHERE prefixOverridesAND | OR...
/trimforeach 用来做迭代拼接的通常会与SQL语句中的IN查询条件结合使用注意到parameterType为List链表或者Array数组后面在引用时参数名必须为list或者array。如在foreach标签中collection属性则为需要迭代的集合由于入参是个List所以参数名必须为list
select idbatchFind resultTypestudent parameterTypelistSELECT * FROM student WHERE id inforeach collectionlist itemitem open( separator, close)#{item}/foreach
/selectsql 可将重复的SQL片段提取出来然后在需要的地方使用标签进行引用
select idfindUser parameterTypeuser resultTypeuserSELECT * FROM userinclude refidwhereClause/
/selectsql idwhereClausewhereif testuser ! nullAND username like %${user.name}%/if/where
/sqlbind mybatis的动态SQL都是用OGNL表达式进行解析的如果需要创建OGNL表达式以外的变量可以用bind标签
select idselectBlogsLike resultTypeBlogbind namepattern value% _parameter.getTitle() % /SELECT * FROM BLOGWHERE title LIKE #{pattern}
/select关联查询
使用 标签以及和 子标签进行关联查询
延迟加载
定义
在关联查询时利用延迟加载先加载主信息。需要关联信息时再去按需加载关联信息
优点
这样会大大提高数据库性能因为查询单表要比关联查询多张表速度要快。
用法
在mybatis中resultMap标签 的association标签和collection标签具有延迟加载的功能。
原理
开启前
第一种方法我们直接关联查询出所有订单和用户的信息select * from orders o ,user u where o.user_id u.id;
开启后
第二种方法分步查询首先查询出所有的订单信息然后如果需要用户的信息我们在根据查询的订单信息去关联用户信息select * from orders;select * from user where iduser_id
逆向工程
mybatis官方提供了mapper自动生成工具mybatis-generator-core来针对单表生成PO类以及Mapper接口和mapper.xml映射文件。针对单表可以不需要再手动编写xml配置文件和mapper接口文件了非常方便。美中不足的是它不支持生成关联查询。一般做关联查询就自己单独写SQL就好了。