面对一个框架,最重要的不是说回用其代码就可以了,我们需要了解其思想,这样才能更快更好的掌握这个框架。而对于一个框架,最重要的就是其配置文件的作用及功能了。下面,我就来谈一谈我今天遇到的这个MyBatis框架。
核心思想
MyBatis的核心思想就是为了简化开发人员在编写和数据库打交道的时候的持久化的复杂的操作。其工作流程我们先不深究,就看看它实现的功能吧。那我们其实可以类比自己写的代码。我们实现和数据库打交道的操作不就是连接数据库,创建相关的JavaBean对象,然后使用DAO层的语法,借助于Service层的桥接功能实现了最终的交互的吗?其实MyBatis的工作也是这样的,只不过它被封装好了而已,我们只需要按照它规定的步骤就可以完成同样的工作,而且可以大大的减轻开发人员的劳动,减轻负担。
而这个框架的底层的细节,就是基于配置文件来完成的。下面我们就分开来讨论一下这些配置文件及其作用。
首先是mybatis-config.xml
当然了,这个文件的名称是随意取的,但是为了见名知意,我还是取了这个名字。其完成的作用就是:
- 数据库连接的配置信息
- JavaBean的映射关系声明
那么我们来看一个例子吧:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-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:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="mysql" />
</dataSource>
</environment>
</environments>
<!-- 下面的这个mapping是必须的,其作用就是和bean对象连接起来 -->
<mappers>
<mapper resource="orm/UserinfoMapper.xml"/>
</mappers>
</configuration>
想必,很清晰的逻辑了吧。至于那个mapper标签里面的信息,我们稍后再叙。
generatorConfig.xml
这个文件的作用就是帮助我们生成相应的JavaBean的,所以我们肯定要制定包名啊,工程名啊,对应的数据库中表项的信息啊什么的。还是看下面的一个小案例吧。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration >
<context id="context1" >
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="mysql" />
<javaModelGenerator targetPackage="orm" targetProject="MyBatisTest" />
<sqlMapGenerator targetPackage="orm" targetProject="MyBatisTest" />
<javaClientGenerator targetPackage="orm" targetProject="MyBatisTest" type="XMLMAPPER" />
<table schema="dbo" tableName="userinfo" >
<!-- <columnOverride column="???" property="???" /> -->
<!-- 下面的这个标签的作用是对于数据库表中的某些选项进行逐渐的自增长的设置,防止数据库中的表中数据项的异常错误! -->
<!-- <generatedKey column="id" sqlStatement="mysql" identity="true"/> -->
</table>
</context>
</generatorConfiguration>
从标签中我们不难看出
- jdbcConnection 数据库连接信息
- javaModelGenerator JavaBean信息
- sqlMapGenerator 映射信息
- javaClientGenerator 客户端的映射信息
- table 数据库表中的相关的信息
完成了上面的这两步,基本上已经算是完成了工作量的一半了。剩下的就是一些我们比较熟悉的操作了。
修改mapper.xml
这里我用到的词语是修改而不是创建,这是因为eclipse上的mybatis generator 插件会使用我们上面创建的那两个配置文件自动的帮助我们生成XXXXMapper.xml文件。我们需要做的就是在这个文件的基础上,进行我们需要的CRUD的语句的修改就可以了。但是说起来简单,真正的做起来才能理解框架设计人员的良苦用心。下面我们来看一看,这个mapper文件的内容吧。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="orm.UserinfoMapper" >
<resultMap id="BaseResultMap" type="orm.Userinfo" >
<!--
WARNING - @mbggenerated
This element is automatically generated by MyBatis Generator, do not modify.
This element was generated on Mon Apr 25 12:50:38 CST 2016.
-->
<id column="id" property="id" jdbcType="INTEGER" />
<result column="username" property="username" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
</resultMap>
<sql id="Example_Where_Clause" >
<!-- ////////////////////////////////////////////////////////我的CRUD语法开始 -->
<select id="selectAllUserinfo" resultMap="BaseResultMap" parameterType="orm.Userinfo">
select * from userinfo
</select>
<!--官方自动生成的一个文件-->
<select id="selectByExample" resultMap="BaseResultMap" parameterType="orm.UserinfoExample" >
<!--
WARNING - @mbggenerated
This element is automatically generated by MyBatis Generator, do not modify.
This element was generated on Mon Apr 25 12:50:38 CST 2016.
-->
select
<if test="distinct" >
distinct
</if>
<include refid="Base_Column_List" />
from userinfo
<if test="_parameter != null" >
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null" >
order by ${orderByClause}
</if>
</select>
<update id="updateByPrimaryKey" parameterType="orm.Userinfo" >
<!--
WARNING - @mbggenerated
This element is automatically generated by MyBatis Generator, do not modify.
This element was generated on Mon Apr 25 12:50:38 CST 2016.
-->
update userinfo
set username = #{username,jdbcType=VARCHAR},
password = #{password,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
</update>
<update id="updateByExampleSelective" parameterType="map" >
<!--
WARNING - @mbggenerated
This element is automatically generated by MyBatis Generator, do not modify.
This element was generated on Mon Apr 25 12:50:38 CST 2016.
-->
update userinfo
<set >
<if test="record.id != null" >
id = #{record.id,jdbcType=INTEGER},
</if>
<if test="record.username != null" >
username = #{record.username,jdbcType=VARCHAR},
</if>
<if test="record.password != null" >
password = #{record.password,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null" >
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
映入眼帘的可能就是这些标签了
- mapper 作为根节点,想一想刚才的mybatis-config.xml文件,我们是不是有了一些灵感呢?这不就相当于一个include 的作用嘛。
- resultMap 这是本文件中声明的一个数据类型,这里返回的是一个自定义的数据结构,关联了数据库的表项。不过我们可以写成其他的。
- select sql语句所对应的操作。选择一个或者多个或者所有
- insert sql的插入语句
- delete sql的删除语句
- update sql的更新的语句
然后是下面的一些相关的属性:
- namespace 所谓命名空间,作用就是唯一的给出一个访问的地址,好让我们唯一的访问内容。
- parameterType 参数类型,就是一会你将会看到的SqlSession中某些方法的第二个参数咯。可以是map,int,等等吧。常用的数据类型要根据在刚才的CRUD标签中的怪异的#{}表达式有关。这一点我们心中一定要做到心中有数,不然的话,对于理解这里面的操作就有可能不到位了。
- resultMap 这个属性的含义就是返回的结果的类型,作为返回的结果,这句话还是很必要滴。
- id 这个属性是最常用的咯。在SqlSession的第一个参数中,配合namespace 便可以唯一的指定框架操作的究竟是哪一个CRUD语句。这样我们也可以方便的维护我们的代码。多好。
还有就是特殊的怪异的表达式#{values}:
这好像是所有框架中最常用的一个表达式了吧。其底层相关于一个域的概念,这一点,我们不难从JSTL的使用上看到一点端倪。或者jsp自带的那些个对象也有其身影。实现了的就是从域中取出key对应的values.如果对着一个用法仍然感到模糊的话,那就尝试着记忆一下吧。
使用Servlet进行测试
一般来说,刚才的生成的那些个东西,就是底层的模块了。而业务逻辑方面MyBatis也相当于给我们封装好了一整套的api。我们只需要会调用这些api就可以了。下面还是从一个简单的小例子入手吧。
package test;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import orm.Userinfo;
/**
* Servlet implementation class TestMyBatis
*/
@WebServlet("/TestMyBatis")
public class TestMyBatis extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public TestMyBatis() {
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
try {
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
Userinfo userinfo = sqlSession.selectOne("orm.UserinfoMapper.selectAllUserinfo", 1);
System.out.println(userinfo.getUsername());
System.out.println(userinfo.getPassword());
sqlSession.commit();
sqlSession.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
我们需要掌握的就是这几个对象的使用。
- SqlSession 今后的最核心的操作对象
- SqlSessionFactory SqlSession他爹,以得到SqlSession对象
- SqlSessionFactoryBuilder SqlSessionFactory他爹。以得到SqlSessionFactory对象
这样的比喻够简练直白了吧。(^__^) 嘻嘻……
然后对于SqlSession对象的操作,只需要掌握它的方法中两个参数的使用即可。
我们可以轻松的从上面的小例子中掌握这一用法。
最后的总结
其实,这个框架,能掌握到这里也只能算是刚入门了。这篇博客是我本人接触的第一个框架之后的两个小时后写的一个感悟,其实入门还是很简单的。但是要想真正的掌握这一个框架,光知道这些真的是远远不够的。我们需要更多的实战来丰富自己的知识。
如果说这里面可以有什么改进的话,我觉的能把SqlSession整体完成一个大的封装的话,可可能效果会更好。不说别的,仿照我们了解的数据库的Connection对象,不就可以完成了吗?照猫画虎,应该会很容易实现的。这样效率和代码的维护等等都会有提升。