MyBatis 的前身就是iBatis,是一个数据持久层(ORM)框架。 MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis对JDBC进行了一次很浅的封装。
以前也学过iBatis,因为MyBatis是iBatis的升级版本,最初以为改动应该不大,实际结果是MyBatis对配置文件进行了一些大的改动,使整个框架更加方便人性化。
如果需要学习MyBatis,建议大家去MyBatis Google Code下载最新的API:http://code.google.com/p/mybatis/
注意api是有中文的,我想这对广大中国同行们是一个很不错的消息。
一、configuration配置文件与hibernate一样,MyBATIS也需要核心配置文件来指定数据源、连接池和ORM映射文件等基础数据。下面是一个简单的配置
注意:<?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"> <!-- 注意:每个标签必须按顺序写,不然蛋疼的DTD会提示错误:The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,plugins?,environments?,mappers?)". --> <configuration> <!-- 属性配置 --> <properties resource="com/mybatisdemo/config/mysql-jdbc-connection.properties"> <!-- 相同属性:最高优先级的属性是那些作为方法参数的,然后是资源/url 属性,最后是 properties元素中指定的属性 --> <property name="username" value="root"/> <property name="password" value="sa"/> </properties> <!-- 设置缓存和延迟加载等等重要的运行时的行为方式 --> <settings> <!-- 设置超时时间,它决定驱动等待一个数据库响应的时间 --> <setting name="defaultStatementTimeout" value="25000"/> </settings> <!-- 别名 --> <typeAliases> <typeAlias alias="UserInfo" type="com.mybatisdemo.entity.UserInfo"/> </typeAliases> <environments default="development"> <!-- environment 元素体中包含对事务管理和连接池的环境配置 --> <environment id="development"> <transactionManager type="JDBC" /> <!-- type分三种: UNPOOLED是每次被请求时简单打开和关闭连接 UNPOOLED的数据源仅仅用来配置以下 4 种属性driver,url,username,password POOLED :JDBC连接对象的数据源连接池的实现,不直接支持第三方数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments> <!-- ORM映射文件 --> <mappers> <mapper resource="com/mybatisdemo/entity/config/UserInfoSqlMap.xml" /> </mappers> </configuration>
(1)XML中的标签顺序不能随便调换,否则会提示错误
(2)MyBATIS使用自带的数据库连接池,不直接支持第三方连接池,不过网上有创建第三方连接池的方法;
(3)以前别名(<typeAliases>)可以再sqlMap标签中创建,但现在要在Configuration标签中创建
(4)该配置文件可随意取名,在读配置文件时指定该XML文件路径即可:
//读取核心配置文件 Reader reader = Resources.getResourceAsReader("com/mybatisdemo/config/Configuration.xml"); //创建SessionFactory实例 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
二、SQL映射的XML文件
此文件类似于IBATIS的<sqlMap>文件,但现在使用的标签为<mapper>。官方这样形容mapper文件作用的:当然如果你将他们和对等功能的JDBC代码比较,你会发现映射文件节省了大约95%的代码量。个人认为mapper文件的重要作用就是把SQL统一存放,方便开发人员复用和维护。下面是一段简单的配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> <!-- namespace用于java代码调用时识别指定xml的mapper文件 --> <mapper namespace="com.mybatisdemo.entity.UserInfo"> <!-- 配置ORM映射 --> <resultMap type="UserInfo" id="user_orm"> <id property="id" column="id"/> <result property="code" column="code"/> <result property="name" column="name"/> <result property="sex" column="sex"/> <result property="phone" column="phone"/> <result property="money" column="money"/> </resultMap> <!-- 用来定义可重用的SQL代码段 --> <sql id="demo_sql"> code,name,sex,phone,money </sql> <insert id="inser_userInfo" parameterType="UserInfo"> <!-- include 引用可重用的SQL代码段 --> INSERT INTO USERINFO(<include refid="demo_sql"/>) VALUES(#{code},#{name},#{sex},#{phone},#{money}) </insert> <update id="update_userInfo" parameterType="UserInfo"> UPDATE USERINFO SET code=#{code} ,name=#{name} ,sex=#{sex} ,phone=#{phone} ,money=#{money} WHERE id=#{id} </update> <select id="selectAll_userInfo" useCache="false" flushCache="true" resultMap="user_orm"> SELECT * FROM USERINFO </select> <select id="selectById_userInfo" parameterType="int" resultType="UserInfo"> SELECT * FROM USERINFO WHERE id= #{id} </select> </mapper>
注意:(1)resultType表示查询结果放到什么对象中,上面resultType = "UserInfo“使用的是com.mybatisdemo.entity.UserInfo的别名,别名是在前面核心配置文件中设置的;
(2)还是resultType,用户好奇:MyBaTIS怎么把每个值放到UserInfo这个JavaBean中,实际上在查询出数据后,MyBaTIS会去UserInfo中查找每个属性,如果属性与表中的列名对应,则会把该列的数据赋给该属性。
(3)如果JavaBean与数据库表字段不对应,可以创建resultMap来实现ORM映射
三、MyBaTIS API
前面XML文件已经实现了数据库连接配置和SQL配置,现在就需要用Java代码去调用XML配置文件的SQL即可实现数据库查询。
与hibernate类似,MyBaTIS也是两个核心对象:SqlSessionFactory 和 SqlSession。SqlSessionFactory 顾名思义就是获取SqlSession对象的工厂,功能类似于JDBC中加载数据库驱动、创建connection连接,所以SqlSessionFactory资源非常重要,推荐该对象保持静态,一直存在,尽量不去销毁。而SqlSession其实就是类似于JDBC的Connection对象,SqlSession对象就能执行数据库的增删改查操作,大家知道每个数据库连接都是非常珍贵的,所以在使用后尽量及时关闭。
为了方便获取SqlSession对象,我们写了一个Util类:
package com.mybatisdemo.demo; import java.io.IOException; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class SessionFactoryUtil { private static final String RESOURCE = "com/mybatisdemo/config/Configuration.xml"; private static SqlSessionFactory sqlSessionFactory = null; private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>(); static { Reader reader = null; try { reader = Resources.getResourceAsReader(RESOURCE); } catch (IOException e) { throw new RuntimeException("Get resource error:"+RESOURCE, e); } sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } /** * Function : 获得SqlSessionFactory * @author : bless<505629625@qq.com> * @return */ public static SqlSessionFactory getSqlSessionFactory(){ return sqlSessionFactory; } /** * Function : 重新创建SqlSessionFactory * @author : bless<505629625@qq.com> */ public static void rebuildSqlSessionFactory(){ Reader reader = null; try { reader = Resources.getResourceAsReader(RESOURCE); } catch (IOException e) { throw new RuntimeException("Get resource error:"+RESOURCE, e); } sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } /** * * Function : 获取sqlSession * @author : bless<505629625@qq.com> * @return : SqlSession */ public static SqlSession getSession(){ SqlSession session = threadLocal.get(); if(session==null){ if(sqlSessionFactory == null){ rebuildSqlSessionFactory(); } //如果sqlSessionFactory不为空则获取sqlSession,否则返回null session = (sqlSessionFactory!=null) ? sqlSessionFactory.openSession(): null; } return session; } /** * Function : 关闭sqlSession * @author : bless<505629625@qq.com> */ public static void closeSession(){ SqlSession session = threadLocal.get(); threadLocal.set(null); if(session!=null){ session.close(); } } }
那么多有准备就绪后,我们来看看我们的重头戏,调用sql:
如果没有学过MyBatis的同学可能会疑问:selectList中传入的参数是什么东西?平常大家都传入的sql语句,这个xx.xx完全看不懂的样子。其实这个"com.mybatisdemo.entity.UserInfo.selectAll_userInfo"就是从前面mapper配置文件中去找对应的sql语句,"com.mybatisdemo.entity.UserInfo"表示配置文件的namespace,"selectAll_userInfo"表示配置文件具体的select标签,update和insert类似。package com.mybatisdemo.demo; import java.util.List; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.SqlSession; import com.mybatisdemo.entity.UserInfo; public class UserInfoDao { @SuppressWarnings("unchecked") public List<UserInfo> findAll(){ SqlSession session = SessionFactoryUtil.getSqlSessionFactory().openSession(); List<UserInfo> lstUser = null; lstUser = session.selectList("com.mybatisdemo.entity.UserInfo.selectAll_userInfo"); session.close(); return lstUser; } @SuppressWarnings("unchecked") public List<UserInfo> findList(int pageNo,int pageSize){ SqlSession session = SessionFactoryUtil.getSqlSessionFactory().openSession(); List<UserInfo> lstUser = null; lstUser = session.selectList("com.mybatisdemo.entity.UserInfo.selectAll_userInfo", null, new RowBounds((pageNo-1)*pageSize, pageSize)); session.close(); return lstUser; } public UserInfo findById(int id){ SqlSession session = SessionFactoryUtil.getSqlSessionFactory().openSession(); UserInfo user = (UserInfo) session.selectOne("selectById_userInfo", id); session.close(); return user; } public void insert(UserInfo user){ SqlSession session = SessionFactoryUtil.getSqlSessionFactory().openSession(); session.insert("com.mybatisdemo.entity.UserInfo.inser_userInfo", user); session.commit(); session.close(); } public void update(UserInfo user){ SqlSession session = SessionFactoryUtil.getSqlSessionFactory().openSession(); session.update("com.mybatisdemo.entity.UserInfo.update_userInfo", user); session.commit(); session.close(); } public static void main(String[] args) { List<UserInfo> lst = new UserInfoDao().findList(3,2); for (UserInfo userInfo : lst) { System.out.println(userInfo.getId()+" "+userInfo.getName()); } } }
学习:http://blessht.iteye.com/blog/1097005
分析的很详细......