Mybatis学习小记
2016-05-22 20:06
525 查看
Mybatis学习小结
最近在学习Java的一些框架,Spring,Mybatis这些,总有点浮于表面的感觉,这里先记录一下使用的小知识。1.初级尝试
这部分记录一下我第一次用Mybatis以及Spring做的小代码,比较简单,主要涉及环境的配置以及简单的使用,后续部分会有其他更深入的使用总结。1.1 准备工作
这里准备一些基本的jar包,我是用maven管理的。用到的jar包如下。这里要特别注意mybatis-spring的版本和mybatis的版本需要匹配,否则会出现很多其他问题了。这里我使用了mybatis的3.1.0版本,mybatis-spring使用的是1.1.1的版本,mysql-connector使用的是5.1.6的版本。<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency>
Tips
这里做一个小提示,连接mysql的connector的版本需要和数据库的版本匹配,否则在项目启动的时候会出现一系列莫名其妙的错误。查看mysql版本的方式:
在os x系统中,mysql的安装位置是在/usr/local/mysql下,因此可以进入该目录的bin文件夹下,执行mysql脚本文件,来查看mysql的版本。执行status命令,便可看到我的mysql版本是5.1.63,因此我就选择了5.1.6这个connector。
1.2 Mybatis 基本配置
这里使用了spring-mybatis框架,因此注入SqlSessionFactory方法比直接使用mybatis要简洁一点。这里需要使用SqlSessionFactoryBean来让spring管理。SqlSessionFactoryBean需要注入datasource。datasource这个bean向下面这样写:<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/m_storage"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean>
写完datasource就可以写SqlSessionFactoryBean这个bean了,如下所示,这里的dataSource就是上面声明的那个bean。这里的mybatis-mapper.xml是配置mybatis映射等内容的配置文件,之后再介绍。
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations" value="/WEB-INF/mybatis-mapper.xml" /> </bean>
以上的两个bean我定义在data-source.xml,并放在WEB-INF文件夹下。在web.xml中我们添加一个Listener,即ContextLoaderListener,它能够加载其它配置文件到Spring上下文中。然后再配置一个context-param元素,指定还需要spring加载的文件,使得spring上下文能加载这个文件中定义的bean。
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/data-source.xml </param-value> </context-param>
下面来写mybatis-mapper.xml文件,这个文件可以用来配置我们需要使用的SQL语句。它的定义如下所示,namespace这个命名空间可以用来索引这些sql代码。
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.justyoung.Mapper"> <select id="selectFile" parameterType="int" resultType="hashmap"> SELECT * FROM FILES WHERE ID = #{id} </select> </mapper>
1.3 Java代码
先定义几个Bean,这里我采用注解的方式来生成Bean,这些Bean包括了SqlSessionFactory,以及SqlSessionFactoryBean。SqlSessionFactoryBean
这里的SqlSessionFactoryBean我定义在了data-source.xml文件中,因此可以直接通过autowire注解进行注入。
SqlSessionFactory
通过定义一个set方法,用来注入SqlSessionFactory。这样就可以直接通过SqlSessionFactory来生成SqlSession。因为默认情况下Spring生成bean对象的方式是单例,因此在需要使用SqlSessionFactory的地方直接利用autowire注入SqlSessionFactory是一个很好的方式。
package org.justyoung.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; @Configuration @EnableAspectJAutoProxy public class AppConfig { @Autowired SqlSessionFactory sqlSessionFactory; @Autowired SqlSessionFactoryBean sqlSessionFactoryBean; @Bean public SqlSessionFactory setSqlSessionFactory() throws Exception { return sqlSessionFactoryBean.getObject(); } }
再编写使用mybatis的Java代码,这里我写在Controller中的一个方法里,如下所示。这里我在mybatis-mapper.xml中定义了一个select标签,它的resultType是一个hashmap,因此,我们可以通过一个HashMap来获得查询的所有内容。
@Autowired SqlSessionFactory sqlSessionFactory; @RequestMapping("/testdatabase") @ResponseBody public String getTable(@RequestParam String fileid) { SqlSession sqlSession = null; try { sqlSession = sqlSessionFactory.openSession(); HashMap<Object, Object> map = sqlSession.selectOne("org.justyoung.Mapper.selectFile", 5); StringBuilder sb = new StringBuilder(); for (Map.Entry<Object, Object> item : map.entrySet()) { sb.append(item.getKey()); sb.append(" "); sb.append(item.getValue()); sb.append("\n"); } return sb.toString(); } finally { if (sqlSession != null) sqlSession.close(); } }
好了,现在可以测试一下代码了,在浏览器中访问刚才写的方法,得到如下结果,从结果中,可以看出HashMap的每一项key对应于数据库表的列名,value代表了列的值。因此我们通过HashMap就能访问表的所有列了,十分方便。
到此,关于Mybatis的配置以及初级使用就总结完了,下面的章节将总结关于Mysql使用的更深入的部分。
2. Mybatis使用总结
在这一部分,我根据Mybatis官方文档的内容,对mybatis进行试验操作,并记录操作的方法和结果。2.1 使用POJO对象
前面的查询,我使用的是HashMap对象来持有查询的结果,但是Mybatis框架是支持将查询结果根据我们的配置注入到一个对象中的。接下来我就尝试一下这种做法。首先定义一个Java对象,用这个对象来保存刚才FILES表的一行数据。这个对象是根据我们的File表定义的,全部都是String成员。
package org.justyoung.dao; public class Files { String id; String fileName; String sha1; String chunks; String createTime; public String getId() { return id; } public String getFileName() { return fileName; } public String getSha1() { return sha1; } public String getChunks() { return chunks; } public String getCreateTime() { return createTime; } public String toString() { return this.id + " " + this.fileName + " " + this.sha1 + " " + this.chunks + " " + this.createTime; } }
接着,修改mybatis-mapper.xml中的内容,如下所示。这里我们把select标签中的resultType属性删除,替换为resultMap属性。然后再声明一个resultMap标签,在标签中定义数据库表的内容和对象属性的对应关系。resultMap中的id属性用于唯一索引这个resultMap,type属性指明它要映射的对象类型。resultMap标签下有几个子节点,这几个子节点包含两种类型,分别是id标签和result标签。
id: 根据mybatis官方文档的信息,给resultMap声明id可以提高整体效能,因此可以把列表的主键列声明为id。
result: 此标签可以提供数据库表列和对象属性的对应信息。
上面两个子标签的用法相似,它们的property属性指代对象的属性名,column属性指示数据库表的列名。这两者之间的唯一不同是 id 表示的结果将是当比较对象实例时用到的标识属性。这帮助来改进整体表现,特别是缓存和嵌入结果映射(也就是联合映射) 。
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.justyoung.Mapper"> <select id="selectFile" parameterType="int" resultMap="FilePojo"> SELECT * FROM FILES WHERE ID = #{id} </select> <resultMap id="FilePojo" type="org.justyoung.dao.Files"> <id property="id" column="ID" /> <result property="fileName" column="FILE_NAME" /> <result property="sha1" column="SHA1" /> <result property="chunks" column="CHUNKS" /> <result property="createTime" column="CHUNKS" /> </resultMap> </mapper>
再来编写读取数据库操作的Java代码,如下所示。sqlSession的select方法是一个泛型方法,因此可以返回我们指定的类型,这里就返回的是我们自己定义的Files对象。
@RequestMapping("/testdatabasepojo") @ResponseBody public String getTablePojo(@RequestParam String fileid) { SqlSession sqlSession = null; try { sqlSession = sqlSessionFactory.openSession(); Files f = sqlSession.selectOne("org.justyoung.Mapper.selectFile", 5); return f.toString(); } finally { if (sqlSession != null) sqlSession.close(); } }
上面代码运行后的执行结果如下,我们顺利地从数据表中将存储的数据取出了。从这个过程可以看出使用对象映射数据库表的内容是十分方便的。
2.2 关联查询
2.2.1 一对多
先来讨论一对多的情形,我们的例子中,一个文件由多个文件块组成,因此我们给Files类添加一个Fragment类型的ArrayList,用来保存多个对象。这个Fragment类型的声明如下所示。public class Fragmentations { String id; String fragmentationName; String belongsID; String orders; String location; String updateTime; @Override public String toString() { return this.id + " " + this.fragmentationName + " " + this.belongsID + " " + this.orders + " " + this.location + " " + this.updateTime; } }
然后,再前面声明的Files类型中添加ArrayList属性,如下所示。
public class Files { String id; String fileName; String sha1; String chunks; String createTime; ArrayList<Fragmentations> fList; public String toString() { StringBuilder sb = new StringBuilder(id); sb.append("\n"); sb.append(fileName); sb.append("\n"); sb.append(sha1); sb.append("\n"); sb.append(createTime); sb.append("\n"); for (Fragmentations f : fList) { sb.append(f); sb.append("\n"); } return sb.toString(); } }
接下来要配置mybatis-mapper.xml文件,添加如下所示的内容。
我往xml文件中添加了id为selectFragmentation的select标签,在这个标签中,写了关联查询的sql语句,即查询所有文件和它们对应的几个文件块的信息,这个标签的返回结果绑定着resultMap,它的id是FileWithCollection。
在id为FileWithCollection的resultMap中,有一个collection子标签,它可以映射一个集合,集合中存储着多个我们指定的类型,从而做到一对多关联查询的存储。collection标签的property属性指定了映射到Java对象的属性名称,ofType指定了集合中存储元素的类型,这里就指定了我们刚才声明的Fragmentation类型,resultMap属性指定了Fragmentation对象中的属性和数据库表列的对应关系,和前面提到的resultMap是一样的,这里我们指定了id为fragmentation的resultMap,columnPrefix属性指定了我们将在fragmentation中的每一列前添加上一个前缀来作为数据库表的列名进行映射,从而使fragmentation这一resultMap能被复用,即不用修改这一resultMap中result或id子标签的column属性就能被不同的查询引用。
id为fragmentation的resultMap和前面所说的resultMap声明是一样的,就不再赘述了。
<select id="selectFragmentation" resultMap="FileWithCollection"> SELECT fi.id as fid, fi.FILE_NAME as filename, fi.SHA1 as fsha1, fi.CREATE_TIME as create_time, f.BELONGS_ID as frag_BELONGS_ID, f.FRAGMENTATION_NAME as frag_FRAGMENTATION_NAME, f.ID as frag_ID, f.LOCATION as frag_LOCATION, f.UPDATE_TIME as frag_UPDATE_TIME FROM fragmentations as f, files as fi where f.BELONGS_ID = fi.id; </select> <resultMap id="FileWithCollection" type="org.justyoung.dao.Files"> <id property="id" column="fid" /> <result property="fileName" column="filename" /> <result property="sha1" column="fsha1" /> <result property="createTime" column="create_time" /> <collection property="fList" ofType="org.justyoung.dao.Fragmentations" resultMap="fragmentation" columnPrefix="frag_" /> </resultMap> <resultMap id="fragmentation" type="org.justyoung.dao.Fragmentations"> <id property="id" column="ID" /> <result property="belongsID" column="BELONGS_ID" /> <result property="fragmentationName" column="FRAGMENTATION_NAME" /> <result property="location" column="LOCATION" /> <result property="updateTime" column="UPDATE_TIME" /> </resultMap>
在写一点操作Mybatis的代码,非常简单,如下所示。
@RequestMapping("/testdatabaseList") @ResponseBody public String getTableWithList() { SqlSession sqlSession = null; try { sqlSession = sqlSessionFactory.openSession(); Files f = sqlSession.selectOne("org.justyoung.Mapper.selectFragmentation"); return f.toString(); } finally { if (sqlSession != null) sqlSession.close(); } }
运行效果如下图所示,那个null是由于我们没有从数据库中检索相关的属性,也没有在resultMap中声明这一属性,因此它就是null。
2.2.2 一对一查询
一对多查询可以使用collection,一对一查询可以使用association。这里总结一下使用association的方法。这里我直接将数据库的内容修改为一个文件对应一个文件块,即一行Files对应一行Fragmentation。先修改Files类型的定义,删除List属性,直接添加Fragmentation属性,如下所示:
Fragmentations fList; public String toString() { StringBuilder sb = new StringBuilder(id); sb.append("\n"); sb.append(fileName); sb.append("\n"); sb.append(sha1); sb.append("\n"); sb.append(createTime); sb.append("\n"); sb.append(fList.toString()); return sb.toString(); }
然后再修改mapper-mybatis.xml文件,如下所示。在这个文件中对select标签进行修改,使关联的resultMap指向FileWithAssociation。在FileWithAssociation中使用association子标签,在这个子标签里可以关联一个其他的resultMap用来映射Fragmentation对象,这里我们就指定fragmentation作为id的resultMap标签。
<select id="selectFragmentation" resultMap="FileWithAssociation"> SELECT fi.id as fid, fi.FILE_NAME as filename, fi.SHA1 as fsha1, fi.CREATE_TIME as create_time, f.BELONGS_ID as frag_BELONGS_ID, f.FRAGMENTATION_NAME as frag_FRAGMENTATION_NAME, f.ID as frag_ID, f.LOCATION as frag_LOCATION, f.UPDATE_TIME as frag_UPDATE_TIME, f.ORDERS as frag_ORDERS FROM fragmentations as f, files as fi where f.BELONGS_ID = fi.id; </select> <resultMap id="FileWithAssociation" type="org.justyoung.dao.Files"> <id property="id" column="fid" /> <result property="fileName" column="filename" /> <result property="sha1" column="fsha1" /> <result property="createTime" column="create_time" /> <association property="fragmentation" javaType="org.justyoung.dao.Fragmentations" resultMap="fragmentation" columnPrefix="frag_" /> </resultMap> <resultMap id="fragmentation" type="org.justyoung.dao.Fragmentations"> <id property="id" column="ID" /> <result property="belongsID" column="BELONGS_ID" /> <result property="fragmentationName" column="FRAGMENTATION_NAME" /> <result property="location" column="LOCATION" /> <result property="updateTime" column="UPDATE_TIME" /> </resultMap>
调用Mybatis的代码不需要修改,直接进行引用,然后得到如下图所示的结果。从下图结果看,我们成功映射了Fragmentation了。
总结
今天就先总结到这里,还有很多如动态SQL,缓存,鉴别器discriminator等内容没有总结,等以后用到了再进行梳理吧。相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树