MyBatis是Apache的一个开源项目,是一个基于Java的持久层框架。它支持普通SQL查询、存储过程以及高级映射。消除了几乎全部的JDBC代码,而且基本不须要手动去设置参数和获取检索结果。使用XML或者注解进行配置,可以映射基本数据元素、Map接口和POJO到数据库。java
MyBatis的功能架构分三层:基础支撑层、数据处理层、API接口层。mysql
基础支撑层sql
负责最基本的功能支撑,包括链接管理、事务管理、配置加载和缓存处理。基础支撑层为上层的数据处理层提供了最基础的支撑。数据库
数据处理层缓存
负责具体的SQL查询、SQL解析、SQL执行和执行结果的映射处理等。数据处理层的主要目的是根据调用的请求完成一次数据库操做。mybatis
API接口层架构
提供给外部使用的接口API,经过这些API来操做数据库。接口层接收到调用请求会马上调用数据处理层来完成具体的操做。oracle
经过配置文件或注解,将SQL的配置信息加载成MappedStatement对象,存储在内存中。app
调用MyBatis提供的API,并将请求传递给下层的数据处理层进行处理。框架
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper .//EN" "http://mybatis.org/dtd/mybatis--mapper.dtd"> <mapper namespace="com.demo.ssm.mapping.userMapper"> <select id="getUser" parameterType="int" resultType="User"> select * from user where id = #{id} </select> </mapper>
其中,namespace属性用来定义mapper的命名空间。<select>
标签中的id属性用来标识sql语句,值必须惟一。parameterType属性用来定义查询时使用的参数类型。resultType属性用来定义查询返回的结果集类型。若是返回的结果集是个列表,应该定义resultMap类型。
<resultMap id="resultListUser" type="User"> <id column="id" property="id" /> <result column="userName" property="userName" /> <id column="userAge" property="userAge" /> </resultMap> <mapper namespace="com.demo.ssm.mapping.userMapper"> <select id="getUsers" parameterType="string" resultMap="resultListUser"> select * from user where username like #{userName} </select> </mapper>
<?xml version="." encoding="UTF-"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config .//EN" "http://mybatis.org/dtd/mybatis--config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:/mybatis" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> <environment> <environments> <mappers> <mapper resource="com.demo.ssm.mapping.userMapper.xml"> </mappers> </configuration>
在实际应用中,常常须要进行关联查询,如一对多、多对一等。这时,就须要在配置文件中使用<association>
标签进行关联。关联查询的配置有两种方式:内部关联和外部关联。
<resultMap id="resultUserArticleList" type="Article"> <id property="id" column="aid" /> <result property="title" column="title" /> <result property="content" column="content" /> <association property="user" javaType="User"> <id property="id" column="id" /> <result property="userName" column="userName" /> <result property="userAge" column="userAge" /> </association> </resultMap> <select id="getUserArticles" parameterType="int" resultMap="resultUserArticleList"> select user.id,user.userName,user.userAge,article.id aid,article.title,article.content from user,article where user.id=article.userid and user.id=#{id} </select>
<resultMap type="User" id="resultListUser"> <id column="id" property="id" /> <result column="userName" property="userName" /> <result column="userAge" property="userAge" /> </resultMap> <resultMap id="resultUserArticleList" type="Article"> <id property="id" column="aid" /> <result property="title" column="title" /> <result property="content" column="content" /> <association property="user" javaType="User" resultMap="resultListUser" /> </resultMap> <select id="getUserArticles" parameterType="int" resultMap="resultUserArticleList"> select user.id,user.userName,user.userAge,article.id aid,article.title,article.content from user,article where user.id=article.userid and user.id=#{id} </select>
很显然,第二种方式更容易达到复用的效果。
在实际应用中,若是查询返回的结果记录不少,就须要作物理分页。不一样的数据库,对应不一样的实现方法。mysql利用limit offset和pagesize来实现,而oracle利用rownum来实现。实现MyBatis的物理分页。
<select id="getUserArticles" parameterType="params" resultMap="resultUserArticleList"> select user.id,user.userName,user.userAge,article.id aid,article.title,article.content from user,article where user.id=article.userid and user.id=#{id} limit #{offset},#{pagesize} </select>
这里的parameterType是传入的参数类或者Map,包含offset和pagesize,以及其余须要的参数。相对来讲,这是比较简单的一种方式。
更通用的一种方式是使用插件进行分页。使用插件的话,须要在MyBatis的配置文件中进行设置。
MyBatis的动态sql语句是基于OGNL表达式的,能够很方便地在sql语句中实现某些逻辑。
<select id="dynamicIf" parameterType="User" resultType="User"> select * from user where 1 = 1 <if test="userName != null"> and userName = #{userName} </if> </select>
若是提供的userName参数不为空,就为sql语句动态添加userName=#{userName}的语句。
<select id="dynamicChoose" parameterType="User" resultType="User"> select * from user where 1 = 1 <choose> <when test="userName != null"> and userName = #{userName} </when> <otherwise> and userName = "sean" </otherwise> </choose> </select>
当userName不为空时,为sql语句动态添加userName=#{userName}。不然,为sql语句动态添加userName="sean"语句。当条件知足时,再也不继续判断,直接跳出choose。当全部条件都不知足时,输出otherwise中的内容。
<select id="dynamicWhere" parameterType="User" resultType="User"> select * from user <where> <if test="userName != null"> userName = #{userName} </if> </where> </select>
在where元素的地方输出一个where,而且可以智能地处理and和or条件。主要用来简化sql语句中where条件判断。
<select id="dynamicTrim" parameterType="User" resultType="User"> select * from user <trim prefix="where" prefixOverrides="and | or"> <if test="userName != null"> userName = #{userName} </if> </trim> </select>
用来给包含的内容加上前缀或后缀,也能够把包含内容的首部或尾部的某些内容覆盖。一般能够利用trim来代替where元素的功能。
<update id="dynamicSet" parameterType="User"> update user <set> <if test="userName != null"> userName = #{userName} </if> </set> where userId = #{userId} </update>
主要用于更新操做,在包含的语句前输出一个set,功能和where元素基本相同。
主要用于构建in条件,能够在sql语句中迭代一个集合。foreach元素主要有几个属性:
不一样状况下,collection属性的值是不一样的。若是传入的是单参数且参数类型是一个List的时候,属性值为list。
<select id="dynamicForeachList" resultType="User"> select * from user where userId in <foreach collection="list" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </select>
若是传入的是单参数且参数类型是一个Array的时候,属性值为array。
<select id="dynamicForeachArray" resultType="User"> select * from user where userId in <foreach collection="array" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </select>
若是传入的是多个参数时,将参数封装成一个Map,属性值为map里的key。
<select id="dynamicForeachMap" resultType="User"> select * from user where userName like "%"#{userName}"%" and userId in <foreach collection="ids" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </select>
因为MyBatis应用程序须要大量的配置文件,若是彻底手工配置,工做量巨大。MyBatis官方推出一个代码生成工具mybatis-generator-core的jar包,以便提升效率。
代码生成工具主要有几个功能:
首先须要建立一个配置文件,进行生成工具的各类设置。
<generatorConfiguration> <!-- 配置mysql驱动jar包路径 --> <classPathEntry location="" <context id="mysql_tables" targetRuntime="MyBatis3"> <!-- 控制生成代码中的注释 --> <commentGenerator> <property name="suppressAllComments" value="true" /> <property name="suppressDate" value="true" /> </commentGenerator> <!-- 数据库链接 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf8" userId="root" password="root"> </jdbcConnection> <javaTypeResolver> <property name="forceBigDecimals" value="false" /> </javaTypeResolver> <!-- model层 --> <javaModelGenerator targetPackage="com.demo.ssm.model" targetProject="src"> <property name="enableSubPackages" value="true" /> <property name="trimStrings" value="true" /> </javaModelGenerator> <!-- mapper映射文件 --> <sqlMapGenerator targetPackage="com.demo.ssm.mapper" targetProject="src"> <property name="enableSubPackages" value="true" /> </sqlMapGenerator> <!-- mapper接口 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.demo.ssm.inter" targetProject="src"> <property name="enableSubPackages" value="true" /> </javaClientGenerator> <!-- 指定要生成代码的数据库表 --> <table schema="mybatis" tableName="user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"> </table> </context> </generatorConfiguration>
而后建立一个代码生成类,用于生成代码。
public class GenMain { public static void main(String[] args) { List<String> warnings = new ArrayList<String>(); boolean overwrite = true; String genCfg = "/mbgConfiguration.xml"; File configFile = new File(GenMain.class.getResource(genCfg).getFile()); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = null; try { config = cp.parseConfiguration(configFile); } catch (IOException e) { e.printStackTrace(); } catch (XMLParserException e) { e.printStackTrace(); } DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = null; try { myBatisGenerator = new MyBatisGenerator(config, callback, warnings); } catch (InvalidConfigurationException e) { e.printStackTrace(); } try { myBatisGenerator.generate(null); } catch (SQLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }