首页 > 代码库 > Mybatis_reveiw之Mybatis官方的一个很简单的Demo
Mybatis_reveiw之Mybatis官方的一个很简单的Demo
上学的时候,一个老师讲了个故事,这个故事的大意是,我们有很多种方式去削苹果,第一种方式,使用指甲刀,第二种方式,使用机床,第三种方式,使用手摇的那种削平果小工具。我们当然都能够完成这个简单的需求,但是使用指甲刀削出来的苹果一定比较坑坑洼洼,不够美观,而且可能会让人感觉到有点没啥食欲。使用机床呢?可能会造成大量的浪费,原本一个美观大方的苹果变成了只能啃几口的正方形。第三个,因为是专门为了削苹果皮而设计的,理论上是最合适用来解决削苹果这个问题的解决方案。
一个好的架构,其实要做的事情是非常简单的,除了深入理解一些架构的原理和组成要素之外,此外就是选择一个合适的技术来解决特定的问题。我们很多人说hibernate不如ibatis好,或者是struts1不如struts2.x好云云,可能也是因为个人的喜好来武断的判断一些问题吧,任何一个技术都有其存在的意义和优势的。我之前非常喜欢混itpub论坛,我一直都记着一个Oracle高手的个性签名中的一句话,大意就是每个Oracle的功能都有特定的解决问题的,没有更好的技术,只有更合适的技术。
为了增加对Mybatis的理解,也为了提高自己的英语水平,用这几天的空闲时间来研究一下Mybatis的官方文档,官方的链接地址在这个地方:
http://mybatis.github.io/mybatis-3/getting-started.html
相对来说,Mybatis的文档还是相当不错的,因为有一些富有爱心的人将官方的文档翻译成中文,这确实让我们这些看着中文文档的程序员们舒服多了。
闲话少叙,进入Mybatis的第一个入门的Demo。
第一步、创建一个Eclipse项目,在Mysql上面创建一张映射表
这里我们就使用Eclipse创建一个最简单的Java Project就好了,MyBatis说白了也是实现VO到数据库表的映射,所以我们准备类文件以及数据库的表。类的定义如下:
<span style="font-family:KaiTi_GB2312;font-size:14px;">public class Tiger { private String name; private double weight; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); long temp; temp = Double.doubleToLongBits(weight); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Tiger other = (Tiger) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (Double.doubleToLongBits(weight) != Double .doubleToLongBits(other.weight)) return false; return true; } @Override public String toString() { return "Tiger [name=" + name + ", weight=" + weight + ", age=" + age + "]"; } } </span>
数据库表的定义如下:
<span style="font-family:KaiTi_GB2312;font-size:14px;">create table tiger1( id int(5), name varchar(30), age int(4), weight double ) </span>
第二步、从网上找到Mybatis的jar包
从网上百度一下就可以找到Mybatis的jar包下载的地方,我们最好是将Mybatis的源代码的jar包和依赖的jar包都扔到自己的DEMO空间下面,方便后面的学习。
点击我们的JavaProject,然后选择属性,找到buildPath将Mybatis下面的jar包引入到当前的项目中。
下面是我引入的jar包的列表:
asm-3.3.1.jar
cglib-2.2.2.jar
commons-logging-1.1.1.jar
javassist-3.17.1-GA.jar
log4j-1.2.17.jar
log4j-api-2.0-rc1.jar
log4j-core-2.0-rc1.jar
mybatis-3.2.6.jar
mysql-connector-java-3.1.6-bin.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
第三步、建立Mybatis的配置文件Mybatis-config.xml文件
在src文件夹的下面创建了一个文件,将其命名为MyBatis-config.xml,里面的内容如下:
<span style="font-family:KaiTi_GB2312;font-size:14px;"><?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> <settings> <setting name="logImpl" value=http://www.mamicode.com/"LOG4J"/>>下面是对这个文件中的元素进行的简单介绍:
MyBatis文件的内容是非常复杂的,这里只是几个必要的文件,上面的第一行,也就是?xml的一行,是XML文件要求的,我们在xml文件中都会看到这一行的内容。第二行的内容是用来解析当前XML的dtd文件的,dtd文件中规定了当前的文件由什么内容组成,对XML起了约束作用。根据XML的规范,当前的XML只有一个根元素,这个根元素的名字被命名为configuration,这个基本的XML中,含有了三个子节点,第一个子节点是setting,第二个子节点的内容是environments第三个子节点的内容是mapper。当然,它可以有更多的配置,但基于当前的文档,我们依次来看这三个节点的作用。
第一个节点是setting,顾名思义,这个是mybatis的配置项,一个软件的灵活程度取决于可以配置的项。在这一点上mybatis提供了大量的配置项,logImpl=LOG4J这里,我们采用这样的配置命令MyBatis采用Log4j来实现日志功能。
第二个节点是environments,在这个项目中,可以配置多个环境,在这个节点中,我们配置的是数据库相关的信息,默认的环境是development,这个节点中transactionManager是用来配置事务属性的,事务在数据库处理的作用的重要性是毋庸置疑的。如何配置事务也是在框架设计中一个非常重要的事情,可以这么说,凡是影响到业务数据准确性的设置,都是非常严重,并且必须给予充分重视的。下面的dataSource是用来配置dataSource所需要的必要选项,使用一个dataSource我们必须要提供必要的信息,这些信息主要是用来描述连接到哪一个数据库以及使用什么样子的信息来连接数据库:数据库的URL地址,端口号,使用什么样子的驱动,用户名,密码,在这个DEMO中,上面的配置采用了POOLED的数据源,这样配置项中肯定还有一些关于数据库连接池的配置项,这里我们全部采用默认了。
第三个节点,是mapper,这是一个非常重要的文件,它的主要作用就是建立了Object与数据库表之间的映射关系,更确切的来说,通过在Mapper中配置SQL语句,来建立SQL语句查询结果集与Object的映射关系,从而隐藏java文件中对象与数据库表之间的实现。这其实与Hibernate做的是一个差不多的事情,只是一个是前言中说的机床与削皮机的区别了。
第四步,建立数据库表和SQL语句的映射配置文件tiger.xml文件
在src文件夹的下面,建立一个名字叫做tiger.xml的文件,这个文件主要是建立数据库表与对象的映射关系,这个文件中的语句如下;
<span style="font-family:KaiTi_GB2312;font-size:14px;"><?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="com.samsung.vo.Tiger"> <select id="selectTiger" resultType="Tiger"> select * from Tiger where id = #{id} </select> </mapper> </span>对这个简单的文件的一点描述,第一行,仍旧是我们喜闻乐见的XML的描述符,所有的XML文件中,都很容易找到这一行,第二行,是当前文件的dtd文件。下面就是建立了一个映射mapper,具体描述了如何通过数据库表找到对应的对象。其中的#{id},告诉我们,这个select语句缺少一个名字为id的参数,增加了这个参数之后,就可以执行这条sql语句得到对应的java对象。
第五步、得到SqlSessionFactory对象
根据官方文档中的有关几个重要对象声明周期的描述,我们将SqlSessionFactory通过简单单例模式的方式来创建对象。相关的代码如下,在Src文件夹的下面创建一个名字为: MybatisUtil的文件,这个文件中的内容下:
<span style="font-family:KaiTi_GB2312;font-size:14px;">import java.io.IOException; import java.io.InputStream; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MybatisUtil { private static SqlSessionFactory sqlSessionFactory; public static SqlSessionFactory getSessionFactory() throws IOException { if(sqlSessionFactory==null){ String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); }else{ return sqlSessionFactory; } } } </span>这个工具类的作用就是在第一次请求的SqlSessionFactory的时候实例化一个对象,如果后面继续请求该对象的时候,直接返回该对象的实例。其中,上面的Resources对象是Mybatis提供的用于找到xml文件的一个公共类,我们在使用的时候直接按照上面的顺序调用就可以了。
但是这里需要明白几个概念,这几个概念分别是Resources、SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper对于这五个对象,依次做一个说明:
Resources是Mybatis提供的用于找到资源文件的工具类,其实就是一个比较好用的工具类,这种工具类在框架中是随处可见的,是能够有效的防止重复早轮子的有效措施,其实做的事情是比较简单的,我们完全可以自己写一个,但是写了能有人家已经提供的好么?所以只需要记住这个类可以拿来用就好了。有钳子为什么要用手呢?
SqlSessionFactoryBuilder是用来创建SqlSessionFactory对象的类,这个对象存在的意义就是来创建SqlSessionFactory,他利用我们提供的资源文件或者自己定义的其他对象,创建出一个SqlSessionFactory,看到这个builder我们就可以想象成一个一次性工程的包工队,你给我制造出制造SqlSession的工厂(SqlSessionFactory)之后,就可以解散了,所以这个方法的生命周期,最好的是一个方法级别的,当方法结束了之后,这个包工队就可以解散了,否则我们将会为这个包工队提供生存的吃喝拉撒的资源,这就不划算了,因为他们后面没有活干了,我们还养闲人,这太划不来了。如果再需要怎么办?首先,我们一般碰不到这种需求,其次,就算是需要重建,我们只需要重新组织包工队就ok了。
SqlSessionFactory这个对象,该对象主要是用来生产SqlSession的一个工厂,这个是我们源源不断得到SqlSession的工厂,最好的实践就是,整个项目只保留一个SessionFactory。就类似于我们在玩红色警戒中的那个核电厂,有了这个东西,我们就可以源源不断的获取SqlSession了,但是只需要一个就好了,也就是上面代码中的那个方法。上面是单例模式的实现,如果不懂的话,可以好好体会一下,静态+获取方法,重点在于,这个对象只是被实例一次,而不会实例第二次的。
最后是这个最重要的对象SqlSession,session的英文意思是会话的意思了,会话,就是一次交谈过程。我们可以从这个角度上来记忆这个方法的生存周期,也就是一次会话。从Mybatis的官方文档中的建议,我们可以看到,如果没有DI框架,我们自己调用Mybatis的时候,应该让SqlSession对象的生命周期限制在一次会话中。sqlSession对象的生命周期,出生于SqlSessionFactory.openSession()方法,终结于SqlSession.close()方法。为了保证这个sqlSession是被关闭的,所以要将其写在finally块中。
第六步、编写main方法,完成自己的第一个Mybatis的Demo
上面的文件都写好之后,我们就可以写一个main方法来让我们上面的代码产生作用了,在Src中随便写一个类,然后在里面编写一个main方法,方法的内容如下
<span style="font-family:KaiTi_GB2312;font-size:14px;"> public static void main(String[] args) throws IOException { SqlSessionFactory sessionFactory = MybatisUtil.getSessionFactory(); SqlSession session = sessionFactory.openSession(); try { Tiger tiger = session.selectOne("selectTiger",1); System.out.println(tiger.getAge()); } finally{ session.close(); } } </span>为了看到整个执行的过程,我们可以配置一个简单的log4j.properties让Log4j的配置生效,将含有下面内容的log4j.properties放到src文件夹下:
<span style="font-family:KaiTi_GB2312;font-size:14px;">log4j.rootLogger=debug, stdout com.samsung.mybatis.Tiger=TRACE log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n </span>点击执行,如果前面的步骤没有错误的话,后台就会输出下面的内容:
DEBUG [main] -Logging initialized using ‘class org.apache.ibatis.logging.slf4j.Slf4jImpl‘adapter.
DEBUG [main] -Logging initialized using ‘class org.apache.ibatis.logging.log4j.Log4jImpl‘adapter.
DEBUG [main] -PooledDataSource forcefully closed/removed all connections.
DEBUG [main] -PooledDataSource forcefully closed/removed all connections.
DEBUG [main] -PooledDataSource forcefully closed/removed all connections.
DEBUG [main] -PooledDataSource forcefully closed/removed all connections.
DEBUG [main] -Opening JDBC Connection
DEBUG [main] -Created connection 14962806.
DEBUG [main] -Setting autocommit to false on JDBC Connection[com.mysql.jdbc.Connection@e45076]
DEBUG [main] -==> Preparing: select * from Tigerwhere id = ?
DEBUG [main] -==> Parameters: 1(Integer)
DEBUG [main] -<== Total: 1
100
DEBUG [main] - Resettingautocommit to true on JDBC Connection [com.mysql.jdbc.Connection@e45076]
DEBUG [main] -Closing JDBC Connection [com.mysql.jdbc.Connection@e45076]
DEBUG [main] -Returned connection 14962806 to pool.
看上面的执行过程,大概是:首先创建一个日志的对象类适配器,建立连接池,打开一个JDBC连接,设置当前连接的autoCommit属性,执行preparedstatement,返回查询结果,解析resultset,最后将autocommit设置为true,最后关闭当前的connection,将当前的连接还给连接池。
此外,还可以使用注解的方式来得到SqlSessionFactory以及执行Sql:
另外,Mybatis还支持注解的方式来避免xml文件,使用注解现在有两个优势,第一个优势就是可以使用IDE的自动提示功能,这个功能对于我们这些依赖IDE的开发人员来说是非常有用的,第二个就是可以减少错误的发生,因为XML毕竟是一个文件,基于字符串的,排查字符串的错误是比较麻烦的。
我们将上面的工程修改为注解的方式,如下。
添加一个TigerMapper.java接口文件如下:
<span style="font-family:KaiTi_GB2312;font-size:14px;">import org.apache.ibatis.annotations.Select; public interface TigerMapper { @Select("select * from Tiger where id = #{id}") public Tiger selectTiger(int id); } </span>修改MybatisUtil.java文件如下:
<span style="font-family:KaiTi_GB2312;font-size:14px;">import java.io.IOException; import org.apache.ibatis.datasource.pooled.PooledDataSource; import org.apache.ibatis.mapping.Environment; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.TransactionFactory; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; public class MybatisUtil { private static SqlSessionFactory sqlSessionFactory; public static SqlSessionFactory getSessionFactory() throws IOException { if(sqlSessionFactory==null){ PooledDataSource dataSource = new PooledDataSource(); dataSource.setDriver("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test"); dataSource.setUsername("chenzw"); dataSource.setPassword("7758521"); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("development", transactionFactory, dataSource); Configuration configuration = new Configuration(environment); configuration.addMapper(TigerMapper.class); return new SqlSessionFactoryBuilder().build(configuration); }else{ return sqlSessionFactory; } } } </span>修改main方法内容如下:
<span style="font-family:KaiTi_GB2312;font-size:14px;"> public static void main(String[] args) throws IOException { SqlSessionFactory sessionFactory = MybatisUtil.getSessionFactory(); SqlSession session = sessionFactory.openSession(); try { Tiger tiger = session.getMapper(TigerMapper.class).selectTiger(1); System.out.println(tiger.getName()); } finally{ session.close(); } } </span>执行结果如下
DEBUG [main] - Logginginitialized using ‘class org.apache.ibatis.logging.slf4j.Slf4jImpl‘ adapter.
DEBUG [main] - PooledDataSourceforcefully closed/removed all connections.
DEBUG [main] - PooledDataSourceforcefully closed/removed all connections.
DEBUG [main] - PooledDataSourceforcefully closed/removed all connections.
DEBUG [main] - PooledDataSourceforcefully closed/removed all connections.
DEBUG [main] - Opening JDBCConnection
DEBUG [main] - Createdconnection 32960703.
DEBUG [main] - Settingautocommit to false on JDBC Connection [com.mysql.jdbc.Connection@1f6f0bf]
DEBUG [main] - ==> Preparing: select * from Tiger where id = ?
DEBUG [main] - ==>Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
ziwen
DEBUG [main] - Resettingautocommit to true on JDBC Connection [com.mysql.jdbc.Connection@1f6f0bf]
DEBUG [main] - Closing JDBCConnection [com.mysql.jdbc.Connection@1f6f0bf]
DEBUG [main] - Returnedconnection 32960703 to pool.
这个是一个官方提供的一个最简单的Demo,后续,将在这个Demo的基础上,一步步来探索官方提供的其他特性,从而加深对Mybatis的理解。