博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MyBatis学习笔记
阅读量:4690 次
发布时间:2019-06-09

本文共 13694 字,大约阅读时间需要 45 分钟。

第一章 如何使用MyBatis?1.导入MyBatis核心包及其依赖包2.配置mybatis.xml文件  (1).配置驱动管理器      
(2).配置数据源
(3).配置映射文件
3.书写一个接口,包含将对数据库执行的操作方法 例如: /** * 添加商品信息 * @param goods * @return */ public Integer addGoods(Goods goods);4.配置映射文件(这里是真正书写sql语句的文件) 包含的基本内容有对数据库进行增删改查的SQL语句。 例如:
//sql语句 insert into goods (goodsName,price,unit,madeTime,shui) values (#{goodsName},#{price},#{unit},#{date},#{shui}) //#{}表示占位符;${}表示sql串拼接
...
5.开始执行对数据库的操作 (1).读取配置文件 String resource = "mybatis.xml"; //配置文件的路径名称 InputStream inputStream = Resources.getResourceAsStream(resource); //读取配置文件 (2).获得session工厂,获得session SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); (3).执行 例如: IGoodsDaoMapper goodsDao = session.getMapper(IGoodsDaoMapper.class); goodsDao.insert(Goods goods); (4).session提交 session.commit();/**对数据进行增删改时,一定要记得提交**/ 第二章 查询详解(1)1.在第一章中提到,在对数据库进行查询的时候,我们需要在查询语句中对查询的列名取别名,并且 别名的名称要与java实体类中对应。在本章,我们采用
来对数据库进行基本的查询。 回顾第一章查询代码: //采用取别名的方式
//使用
例如:
//主键
...... //查询语句
采用这种方式进行查询,可以避免每次查询都需要进行取别名的繁琐;并且使用
可以 单独提出,这样如果对一张表进行多次查询的时候,可以使用
的id属性。这样,查询 是不是变得简单多了呢?第三章 查询详解(2)1.在上一章内容中,我们讲到,可以使用
标签来查询,省去了查询时取别名的麻烦。之前 提到的查询都是对一张表进行简单查询。那么,对于两张表,甚至多张表进行查询时,我们往往会遇到 "多对一"或者"一对多"的查询。 例如:多个商品对应一种商品类型或者一种商品类型对应多个商品......2.多对一的查询 方式1:
property:实体类中对应的变量名称 column:数据库中对应的列名 javaType:该属性对应的实体类(包+类) select:对应的查询语句id 例如:
方式一的查询流程: 1.首先将goods表中的数据全部查询出来,包括typeId 2.将查询出来的每一个typeId作为参数传入到id="findGoodsTypeById"的
select goods.*,tb_type.* from goods inner join tb_type on goods.typeId = tb_type.id 方式2显然是在sql语句中进行了改进,避免了产生多次查询的情况。 3.一对多的查询
......
ofType:集合中元素类型 例如:
第四章 查询详解(3)以及动态SQL1.在对一张表进行查询的时候,我们通常会进行模糊查询。 例如:
此处用到了${},而之前我们队参数的传入一直都是#{}。 这里就涉及到了#{}与${}的区别: (1).#{}能够防止SQL注入,而${}不能 在学习过程中,我们发现在一般查询过程中,#{}与${}似乎并没有什么区别,都能查询到我们 想要的结果。 例如: select * from goods where goodsName = #{goodsName} select * from goods where goodsName = '${goodsName}' 但是在动态解析的时候,使用#{}时,会被解析成一个占位符,也就是: select * from goods where goodsName = ? 而${}在动态解析的时候,传入的参数就会被当成一个普通的字符串常量,也就是: select * from goods where goodsName = '哇哈哈' (2).在用${}进行传参的时候,参数变量名必须是parameterType中的属性,并且该属性有对应的 setter()和getter()方法。 在刚才的模糊查询的例子中,我们发现,参数名称为goodsName,而parameterType是Goods实体类 goodsName是Goods实体类中的属性。在这里,如果把goodsName换成name或者其他名称,就会报错。 同样的,加入把parameterType换成其他类型,同样会报相同的错误。因为该类中没有对应的该属性 的setter()和getter()方法。2.动态SQL (1).if判断 例如:
属性: test:if判断的内容,并且test中的变量名称必须是parameterType中的属性,且有对应getter() (2).
循环 例如:
insert into tb_type values
(default,#{typeName})
属性: collection:被循环的类型 item:元素名称 separator:分隔符 #{}中的名称必须与item相同,否则报错 其他动态SQL标签可自行去官网查看。 第五章 MyBatis调用存储过程 在实际开发中,我们常常会去调用存储过程,那么在MyBatis中,如何去调用存储过程呢? (1).对数据库进行增删改,且有返回值时,通常使用Map
做参数 例如: Interface IGoodsTypeMapper中: public void findCntByName(Map
) throws Exception; typeMapper.xml中:
测试类中: IGoodsMapper goodsMapper = session.getMapper(IGoodsMapper.class); Map
parameter = new HashMap
(); parameter.put("type_name", "葫芦娃4"); goodsMapper.getTypeCntByName(parameter); System.out.println("============>"+parameter.get("cnt")); 在测试过程中的map集合,键的名称应当与typeMapper.xml中#{}的名称一致。即: parameter.put("type_name", "葫芦娃4"); #{type_Name,mode=IN,jdbcType=VARCHAR} 存储过程返回的值,会自动放入Map集合中,并且返回结果的键名称就是typeMapper.xml中的名字一致。 (2).对于查询数据库的存储过程 例如: Interface IGoodsTypeMapper中: public List
getTypeInfo() throws Exception; typeMapper中:
测试类中: List
typeList = goodsMapper.getTypeInfo(); for(GoodsType types : typeList){ System.out.println("类型编号:"+types.getId()+"\t"+"类型名称:"+types.getTypeName()); } 第六章 MyBatis缓存机制 MyBatis中包含了一个非常强大的缓存特性,并且配置使用非常方便。缓存能够极大地提升查询效率。 MyBatis中的缓存分为两个级别的缓存,分别为:一级缓存、二级缓存。 1.一级缓存 一级缓存的作用域在sqlSession,默认情况下是开启的。 二级缓存 二级缓存的作用域在nameSpace,需要手动开启和配置。 2.证明一级缓存的存在 IGoodsMapper goodsDao = session.getMapper(IGoodsMapper.class); List
typeList1 = goodsDao.findType(); List
typeList2 = goodsDao.findType(); 执行日志: 11:25:58,099 DEBUG com.xt.dao.IGoodsMapper.findType:145 - ==> Preparing: select tb_type.* from tb_type 11:25:58,187 DEBUG com.xt.dao.IGoodsMapper.findType:145 - ==> Parameters: 11:25:58,245 DEBUG com.xt.dao.IGoodsMapper.findType:145 - <== Total: 28 事实证明,对数据库进行两次查询,但是只发送了一次sql语句。说明第二次的查询结果是从缓存区中拿的。 那么一级缓存在什么情况下会失效呢? (1).在同一个sqlSession执行查询的过程中,进行了增删改操作(强调:同一个sqlSession)。 证明: IGoodsMapper goodsDao = session.getMapper(IGoodsMapper.class); //第一次查询 List
typeList1 = goodsDao.findType(); //增加一条记录 List
typeNames = new ArrayList
(); typeNames.add("boom"); Integer flag = goodsDao.insertGoodsType(typeNames); session.commit(); //第二次查询 List
typeList2 = goodsDao.findType(); 执行日志: 11:31:39,553 DEBUG com.xt.dao.IGoodsMapper.findType:145 - ==> Preparing: select tb_type.* from tb_type 11:31:39,588 DEBUG com.xt.dao.IGoodsMapper.findType:145 - ==> Parameters: 11:31:39,630 DEBUG com.xt.dao.IGoodsMapper.findType:145 - <== Total: 28 11:31:39,652 DEBUG com.xt.dao.IGoodsMapper.insertGoodsType:145 - ==> Preparing: insert into tb_type values (default,?) 11:31:39,653 DEBUG com.xt.dao.IGoodsMapper.insertGoodsType:145 - ==> Parameters: boom(String) 11:31:39,654 DEBUG com.xt.dao.IGoodsMapper.insertGoodsType:145 - <== Updates: 1 11:31:39,655 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction:69 - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5c5a1b69] 11:31:39,660 DEBUG com.xt.dao.IGoodsMapper.findType:145 - ==> Preparing: select tb_type.* from tb_type 11:31:39,661 DEBUG com.xt.dao.IGoodsMapper.findType:145 - ==> Parameters: 11:31:39,667 DEBUG com.xt.dao.IGoodsMapper.findType:145 - <== Total: 29 事实证明:在第一次查询过后,进行了一次增加操作,那么第二次的查询结果并不是从缓存中拿的,而是又进行了一次查询。 为什么要强调同一个sqlSession呢? 刚才的例子中,都是同一个sqlSession,在进行了对数据库的更新后,第二次查询时,并没有从缓存中读取。 现在看下一个例子: SqlSession session1 = sqlSessionFactory.openSession(); SqlSession session2 = sqlSessionFactory.openSession(); //第一个sqlSession1 IGoodsMapper goodsDao1 = session1.getMapper(IGoodsMapper.class); //第二个sqlSession2 IGoodsMapper goodsDao2 = session2.getMapper(IGoodsMapper.class); //sqlSession1第一次查询 List
typeList1 = goodsDao1.findType(); //sqlSession2添加一条数据 List
typeNames = new ArrayList
(); typeNames.add("boom1"); Integer flag = goodsDao2.insertGoodsType(typeNames); session2.commit(); //sqlSession1第二次查询 List
typeList2 = goodsDao1.findType(); //第一次查询结果 for(GoodsType type1 : typeList1){ System.out.println("类型名称:"+type1.getTypeName()); } //第二次查询结果 for(GoodsType type2 : typeList2){ System.out.println("类型名称:"+type2.getTypeName()); } 查询日志: 21:37:52,260 DEBUG com.xt.dao.IGoodsMapper.findType:145 - ==> Preparing: select tb_type.* from tb_type 21:37:52,298 DEBUG com.xt.dao.IGoodsMapper.findType:145 - ==> Parameters: 21:37:52,355 DEBUG com.xt.dao.IGoodsMapper.findType:145 - <== Total: 31 21:37:52,384 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction:136 - Opening JDBC Connection 21:37:52,407 DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource:387 - Created connection 2028371466. 21:37:52,408 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction:100 - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@78e67e0a] 21:37:52,408 DEBUG com.xt.dao.IGoodsMapper.insertGoodsType:145 - ==> Preparing: insert into tb_type values (default,?) 21:37:52,409 DEBUG com.xt.dao.IGoodsMapper.insertGoodsType:145 - ==> Parameters: boom1(String) 21:37:52,413 DEBUG com.xt.dao.IGoodsMapper.insertGoodsType:145 - <== Updates: 1 21:37:52,414 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction:69 - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@78e67e0a] 分析:很显然sqlSession1的第二次查询是从缓存区拿的数据,并没有重新发送sql语句,这样会产生脏读! 这个例子证明了两点: (1).只有在同一个sqlSession中,在查询过程中对数据库进行增删改,一级缓存才会失效。 (2).一级缓存只存在数据库内部共享。 (2).同一个sqlSession,但是查询条件不同。 (3).同一个sqlSession,两次查询期间手动清空了缓存。 3.如何开启二级缓存 (1).在配置文件myBatis.xml中,手动开启。
(2).在映射文件中配置二级缓存的属性
eviction: flushInterval:刷新缓存的时间间隔 size:缓存对象的大小 readOnly:是否只读 4.证明二级缓存生效 SqlSession session = sqlSessionFactory.openSession(); IGoodsMapper goodsDao = session.getMapper(IGoodsMapper.class); List
typeList = goodsDao.findType(); session.close(); SqlSession session2 = sqlSessionFactory.openSession(); IGoodsMapper goodsDao2 = session2.getMapper(IGoodsMapper.class); List
typeList2 = goodsDao2.findType(); 执行日志: 17:27:37,453 DEBUG com.xt.dao.IGoodsMapper.findType:145 - ==> Preparing: select tb_type.* from tb_type 17:27:37,484 DEBUG com.xt.dao.IGoodsMapper.findType:145 - ==> Parameters: 17:27:37,531 DEBUG com.xt.dao.IGoodsMapper.findType:145 - <== Total: 32 17:27:37,531 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction:122 - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@2b552920] 17:27:37,531 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction:90 - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@2b552920] 17:27:37,531 DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource:344 - Returned connection 727001376 to pool. 17:27:37,531 DEBUG com.xt.dao.IGoodsMapper:62 - Cache Hit Ratio [com.xt.dao.IGoodsMapper]: 0.5 由上面的执行结果知道,第一次的查询,向数据库发送了sql语句;但是第二个查询,是直接从二级缓存中读取的数据。 缓存命中为:0.5 第七章 MyBatis注解(1) 在之前的学习过行程中,我们都采用的映射文件的方式来对数据库进行操作。MyBatis还未我们提供了注解,方便我们的使用。 废话不多说,直接上菜。 (1).在之前使用映射文件时,在配置文件mybatis.xml中的
中是这样的:
使用注解后:
(2).在接口中使用注解 例如: /* *查询商品类型信息 */ @Select("select * from goods") @Results( value={ @Result(id=true,property="goodsId",column="goodsId"), @Result(property="goodsName",column="goodsName") } ) public List
findGoods() throws Exception; /* *删除数据(只有一个参数) */ @Delete("delete from tb_type where id = #{id}") public Integer delete(Integer typeId) throws Exception; /* *删除数据(多个参数) */ @Delete("delete from tb_type where id = #{typeId} or typeName = #{typeName}") public Integer delete2(@Param("typeId") Integer typeId,@Param("typeName") String typeName) throws Exception; /* *添加一条数据(返回主键) */ @Insert("insert into goods values (default,#{goodName},#{price},#{unit},#{date},#{shui},#{type.id})") @Option(useGeneratedKeys=true,keyProperty="id",keyColumn="id") public Integer insertGoodsInfo(Goods goods) throws Exception; 注: 当传递多个参数的时候,需要使用@Param来指明参数,否则会报错:参数找不到。第八章 MyBatis注解(2) 在之前的学习过程中,我们对数据库进行操作是通过映射文件,然后学习了注解。但是我们会发现,单纯的 注解用来写SQL语句是不够的。所以本章就为大家介绍XXXXProvider的使用方法。 由于MyBatis相对简单,所以直接上代码: (1).GoodsTypeDao.class中的代码: @SelectProvider(type=SqlProvider.class,method="selectType") @Results( value={ @Result(id=true,property="id",column="id"), @Result(property="typeName",column="typeName") } ) public List
findType(@Param("id")Integer id,@Param("name")String typeName) throws Exception; (2).SqlProvider.class中的代码: public String selectType(Map
param){ return new SQL() .SELECT("*") .FROM("tb_type") .WHERE("id=#{id} or typeName = #{name}") .toString(); } 解析: type:返回sql语句的类 method:返回sql语句的方法 注: *如果只有一个参数,那么在selectType()中,只需传入一个指定类型的参数就行。在使用的过程中, 在findType()中传入相应参数,该参数就会传入selectType()中,然后赋给sql语句中。 *但是有多个参数时,按照刚才的方法就会报错。因此我们通常会在selectType()中传入一个Map<>集合。 在findType()中,可以使用@Param为传入的参数取别名,这个别名就是Map<>集合中元素的键,在传入 实参的时候的值就是Map<>集合中的键的值。 第九章 没有实体类的查询 在之前的学习过程中,我们对数据库进行操作时,都是利用实体类,比如查询,返回的结果集是List
。 那么在日常开发中,我们有时候并不会去写实体类,因为那样很麻烦。(当然,我们会从数据库反向生成实体类) 那么如何在没有实体类的情况下,对数据库进行查询呢? 直接看代码: GoodsMapper.class中: @SelectProvider(type=SqlProvider.class,method="searchGoodsInfo") @Results( value={ @Result(id=true,property="goodsId",column="goodsId"), @Result(property="goodsName",column="goodsName") } ) public List
> searchGoods() throws Exception; 大家可以看到,这里返回的并不是List
,而是List
>。 测试类中: IGoodsMapper goodsDao = session.getMapper(IGoodsMapper.class); List
> goodsList = goodsDao.searchGoods(); for(Map
map : goodsList){ System.out.println("商品名称:"+map.get("goodsName")); } 由此可以看出:当从数据库查询到数据后,会将列名作为Map集合的键,值作为Map集合的值

 

转载于:https://www.cnblogs.com/schCode/p/8985479.html

你可能感兴趣的文章
深入浅出事件流处理NEsper(三)
查看>>
TP框架控制器的空操作
查看>>
【纯干货】4年前想解决的事情,今天才实验成功
查看>>
介绍一个日志记录函数
查看>>
OopenCV复习及函数深入理解(轮廓查询及绘图)
查看>>
老李分享:持续集成学好jenkins之解答疑问
查看>>
茑萝改变了我
查看>>
VC调用DLL
查看>>
一种多继承方案
查看>>
【手绘】A old painting ,drawed in middle school ,grade 8
查看>>
关于C#窗体程序dataGridView控件的用法
查看>>
数学图形之花儿
查看>>
Ruby学习笔记1 -- 基本语法和数据类型, Class
查看>>
tesseract-ocr训练方法
查看>>
react-native开源组件react-native-wechat学习
查看>>
Python之旅:集合
查看>>
表关联关系,表的复制
查看>>
silverlight DataPager控件
查看>>
双系统win+ubuntu无法访问win的盘符
查看>>
PO、VO、BO、POJO、DAO、DTO都是什么对象
查看>>