Mybatis学习小记

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等内容没有总结,等以后用到了再进行梳理吧。

时间: 2024-10-29 19:55:18

Mybatis学习小记的相关文章

git 学习小记之记住https方式推送密码

昨天刚刚学了点git基础操作,但是不幸的是[email protected]给出公告说尽量使用 https 进行操作.可是在用 https 进行 push 时,都需要输入帐号和密码. 各种百度谷歌之后在[email protected]官网找到了解决方法<https方式使用[email protected]设置密码的方式>文中给出了几个方法,并且都非常简单. 关于 cache 缓存方式,我不太喜欢,因为要设置时间,而且会过期.而 store 相应的非常方便,设置全局后,方便多个库使用.当然如果

MyBatis学习总结(五)——实现关联表查询(转载)

孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(五)--实现关联表查询 一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关系. 1 CREATE TABLE teacher( 2 t_id INT PRIMARY KEY AUTO_INCREMENT, 3 t_name VARCHAR(20) 4 ); 5 CREATE TAB

MyBatis学习总结(七)——Mybatis缓存(转载)

孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(七)--Mybatis缓存 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空. 2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,Hash

linux学习小记 (一 )

shell 学习小记: 注意:多看系统脚本  多模仿    su切换用户时需要输入目标用户密码,root(superuser)切换到任何用户都不需要输入密码,- 参数必须要是最后一个(su huhu -) sudo需要输入当前用户密码,拥有sudo特权的用户可以执行 "sudo su -"命令,使用自己的密码切换到root用户 , 所以应该在/etc/sudoers 文件中禁止 sudo 执行su命令 linux文件与颜色: /etc/DIR_COLORS   (命令dircolors

MyBatis:学习笔记(3)——关联查询

MyBatis:学习笔记(3)--关联查询 关联查询 理解联结 SQL最强大的功能之一在于我们可以在数据查询的执行中可以使用联结,来将多个表中的数据作为整体进行筛选. 模拟一个简单的在线商品购物系统,如果我们将用户信息和订单信息都保存在user表中,这样就不存在联结关系,因为我们仅仅操作一张表就好. 但是这是非常不明智的选择,举例来说,一个用户可以拥有多个订单,如果保存在一个表中,势必会导致用户信息的多次出现,因为每个订单绑定的用户信息都是相同的. 所以我们尽量要将不同的信息存储与不同的表中,但

MyBatis学习总结(六)——调用存储过程(转载)

孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(六)--调用存储过程 一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 1 create table p_user( 2 id int primary key auto_increment, 3 name varchar(10), 4 sex char(2) 5 ); 6 7 insert into p_user(name,sex) values('A',"男");

MyBatis学习总结(八)——Mybatis3.x与Spring4.x整合(转载)

孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(八)--Mybatis3.x与Spring4.x整合 一.搭建开发环境 1.1.使用Maven创建Web项目 执行如下命令: mvn archetype:create -DgroupId=me.gacl -DartifactId=spring4-mybatis3 -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false 如下图所示: 创建好的项目如下

mybatis学习笔记(1)

之前做项目的时候,DAO层写了一些spring jdbc,用起来的确不是很方便,今天特意去学习了新的框架:mybatis.把之前用spring-jdbc写的内容换成了mybatis框架搭建的内容. 首先你要到mybatis的官网去下mybatis的jar包:mybatis-3.2.7.jar.由于我是在spring的基础上去搭建mybatis所以还要去弄一个mybatis-spring-1.2.2.jar, 这个连接的包好像在spring官方是找不到的,需要自己去网上找. 进入正题.首先在src

Mybatis学习笔记(二) 之实现数据库的增删改查

开发环境搭建 mybatis 的开发环境搭建,选择: eclipse j2ee 版本,mysql 5.1 ,jdk 1.7,mybatis3.2.0.jar包.这些软件工具均可以到各自的官方网站上下载.首先建立一个名字为 MyBaits 的 dynamic web project 1. 可以创建maven项目,依赖的包mybatis-3.2.0-SNAPSHOT.jar,mysql-connector-java-5.1.22-bin.jar <!-- mybatis包 --> <depe