1.1 MyBatis介绍
MyBatis 世界上流行最广泛的基于SQ语句的ORM框架,由Clinton Begin 在2002 年创建,其后,捐献给了Apache基金会,成立了iBatis 项目。2010 年5 月,将代码库迁致Google Code,并更名为MyBatis.
1.2 与Hibernate比较
- 学习成本:MyBatis简单易学(特别是有SQL语法基础的人),较接近JDBC
- 程序灵活性:MyBatis直接使用SQL,灵活性高
- 程序执行效律:MyBatis效律高
- 可移植性:hibernate较好(与数据库关联在配置中完成,HQL语句与数据库无关)
1.3 适用场合
MyBatis是一个灵活的DAO层解决方案,满足较高的性能要求,可以在很多场合使用,但一般以下场合不建议使用:
- 需要支持多种数据库或数据库有移植要求
- 完全动态SQL,例如:字段都要动态生成
使用的不是关系数据库
1.4 开发步骤(推荐)
- 新建JAVA项目或WEB项目
- 部署jar包(包括数据库驱动包):使用MyBatis需要先下载jar包:下载地址http://code.google.com/p/mybatis
- 编写主配置文件
- 创建数据库及表
- 创建实体类及SQL映射文件
- 编写数据库接口及实现
- 编写测试类及测试
1.5 开发示例
1.5.1 新建项目
新建java项目或web 项目。
1.5.2 导入JAR包
导入mybatis和数据库驱动包、日志包(配置日志配置文件)。
1.5.3 创建myBatis-config.xml
(可以参考用户手册)
<?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"> <!--事务管理类型主要有jdbc和managed,前者依赖于数据源获得的连接,后者依赖于容器 --> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <!-- 如果数据库设置为UTF-8,则URL参数连接需要添加?useUnicode=true&characterEncoding=UTF-8,如下 --> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8" /> <property name="username" value="***" /> <property name="password" value="***" /> </dataSource> </environment> </environments> </configuration>
1.5.4 创建数据库及表
drop database if exists mybatis; create database mybatis CHARACTER SET UTF8; use mybatis; create table dept( dept_id int primary key auto_increment, dept_name varchar(50), dept_address varchar(50) ); insert into dept(dept_name,dept_address) values('研发部一部','广州'); insert into dept(dept_name,dept_address) values('研发部二部','广州'); insert into dept(dept_name,dept_address) values('研发部三部','深圳'); select * from dept;
1.5.5 创建实体类:Dept.java
public class Dept implements Serializable { private Integer deptId; //部门编号 private String deptName;//部门名称 private String deptAddress;//部门地址 public Integer getDeptId() { return deptId; } public void setDeptId(Integer deptId) { this.deptId = deptId; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } public String getDeptAddress() { return deptAddress; } public void setDeptAddress(String deptAddress) { this.deptAddress = deptAddress; } @Override public String toString() { return "Dept [deptId=" + deptId + ", deptName=" + deptName + ", deptAddress=" + deptAddress + "]"; } }
1.5.6 创建SQL映射文件及修改主配置文件
SQL映射文件:DeptMapper.xml(可以参考用户手册)
<?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="cn.it.entity.DeptMapper"> <!-- 一般在查询时使用--> <resultMap type="cn.it.entity.Dept" id="deptResultMap"> <id property="deptId" column="dept_id"/> <result property="deptName" column="dept_name"/> <result property="deptAddress" column="dept_address"/> </resultMap> <!-- 定义插入的sql语句,通过命名空间+id方式被定位 --> <insert id="insert" parameterType="cn.it.entity.Dept"> insert into dept(dept_name,dept_address) values(#{deptName},#{deptAddress}); </insert> </mapper> 修改myBatis-config.xml,加入映射文件信息 <?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"> ………… </environments> <mappers> <mapper resource="cn/it/entity/DeptMapper.xml" /> </mappers> </configuration>
1.5.7 编写数据库操作
包括操作接口及实现,接口略,实现类为:DeptDaoImpl.java
public class DeptDaoImpl { /** * 用于插入数据到dept表。 * @param dept 部门信息 * @return 表示受影响的行数 */ public int insert(Dept dept){ /* * 1.读取配置信息 * 2.构建session工厂 * 3.创建session * 4.启动事务(可选) * 5.数据处理 * 6.提交事务、回滚事务(可选) * 7.关闭session */ int i=0; SqlSession session=null; String config="myBatis-config.xml"; Reader reader = null; try { reader=Resources.getResourceAsReader(config); SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader); session=sqlSessionFactory.openSession(); //事务默认自动启动 //SQL映射文件定义的命名空间+SQL语句的ID定位SQL语句,例如下的:cn.it.entity.DeptMapper.insert i=session.insert("cn.it.entity.DeptMapper.insert",dept); session.commit(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); session.rollback(); }finally{ //关闭reader对象,这里略 session.close(); } return i; } }
1.5.8 编写测试类
需要导入junit包
public class DeptTest { private static DeptDaoImpl deptDaoImpl; @BeforeClass public static void setUpBeforeClass() throws Exception { deptDaoImpl=new DeptDaoImpl(); } @AfterClass public static void tearDownAfterClass() throws Exception { deptDaoImpl=null; } @Test public void testInsert() { Dept dept=new Dept(); dept.setDeptName("市场部"); dept.setDeptAddress("深圳"); int i=deptDaoImpl.insert(dept); System.out.println("受影响行数:"+i); } }
2.基本的CRUD操作
2.1 准备工作(继续使用前面的库表和代码)
2.2 别名与自定义别名
2.2.1 内置别名
对常用的 java 类型,已经内置了一些别名支持。这些别名都是不区分大小写的。(详细参看用户手机)
2.2.2 自定义别名
在myBatis的主配置文件给cn.it.entity.Dept类创建别名Dept,后继的DeptMapper.xml配置文件中可以使用别名
<!-- 通过别名简化对类的使用 --> <typeAliases> <typeAlias type="cn.it.entity.Dept" alias="Dept" /> </typeAliases>
2.3 MyBatisUtil工具类
public class MyBatisUtil { private static final ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>(); private static SqlSessionFactory sessionFactory; private static String CONFIG_FILE_LOCATION = "myBatis-config.xml"; static { try { buildSessionFactory(); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } } private MyBatisUtil() { } /** * Returns the ThreadLocal Session instance. Lazy initialize * the <code>SessionFactory</code> if needed. * * @return Session * @throws Exception */ public static SqlSession getSession() throws Exception { SqlSession session = (SqlSession) threadLocal.get(); if (session == null) { if (sessionFactory == null) { buildSessionFactory(); } session = (sessionFactory != null) ? sessionFactory.openSession() : null; threadLocal.set(session); } return session; } /** * build session factory * */ public static void buildSessionFactory() { Reader reader=null; try { reader=Resources.getResourceAsReader(CONFIG_FILE_LOCATION); sessionFactory = new SqlSessionFactoryBuilder().build(reader); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); }finally{ try { reader.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * Close the single session instance. * */ public static void closeSession(){ SqlSession session = (SqlSession) threadLocal.get(); threadLocal.set(null); if (session != null) { session.close(); } } /** * return session factory * */ public static SqlSessionFactory getSessionFactory() { return sessionFactory; } }
2.3 CRUD操作
2.3.1 新增操作
配置文件DeptMapper.xml使用别名, DeptDaoImpl.java新增方法使用工具类。
修改配置文件DeptMapper.xml(使用别名):
<!--parameterType="Dept"不写时,也能自动根据代码传递的参数Dept自动匹配 内容--> <insert id="insert" parameterType="Dept"> insert into dept(dept_name) values(#{deptName}); </insert>
修改DeptDaoImpl.java新增方法(使用MyBatisUtil.java工具类):
/** * @param dept 部门信息 * @return 保存信息后受影响的行数 */ public int saveDept(Dept dept) { int i = 0; try { session = MyBatisUtil.getSession(); i = session.insert("cn.it.entity.DeptMapper.insertDept", dept); session.commit(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); session.rollback(); } finally { try { MyBatisUtil.closeSession(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } return i; }
2.3.2 修改操作
修改配置文件deptMapper.xml,添加
<update id="update" parameterType="Dept"> update dept set dept_name=#{deptName} ,dept_address=#{deptAddress} where dept_id=#{deptId} </update>
修改DeptDaoImpl.java,添加update方法:
public int update(Dept dept){ SqlSession session = null; int i=0; try { session=MyBatisUtil.getSession(); //方法的第一个参数为DeptMapper.xml文件的命名空间+id i=session.update("cn.it.entity.DeptMapper.update",dept); System.out.println("受影响行数:"+i); session.commit(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); session.rollback(); }finally{ MyBatisUtil.closeSession(); } return i; }
2.3.3 删除操作
修改配置文件deptMapper.xml,添加
<delete id="delete" parameterType="Dept"> delete from dept where dept_id=#{deptId} </delete>
修改DeptDaoImpl.java,添加delete方法:
public int delete(Dept dept){ int i = 0; try { session=MyBatisUtil.getSession(); //方法的第一个参数为DeptMapper.xml文件的命名空间+id i=session.delete("cn.it.entity.DeptMapper.delete",dept); //System.out.println("受影响行数:"+i); session.commit(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); session.rollback(); }finally{ MyBatisUtil.closeSession(); } return i; }
2.3.4 查询操作(返回单条记录)
配置deptMapper.xml文件的resultMap元素及SQL查询语句
<!-- 表字段和实体属性命名一致时可以不配置 --> <resultMap id="deptResultMap" type="Dept"> <id property="deptId" column="dept_id"/> <result property="deptName" column="dept_name"/> <result property="deptAddress" column="dept_address"/> </resultMap> <!—省略其它的配置信息 --> <!—返回单条记录,表字段和对应实体属性命名一致时可以不使用resultMap属性配置,直接使用resultType="返回的全类名或别名",建议使用前者;查询结果为所有字段时,也可以用*表示 --> <select id="selectOne" parameterType="int" resultMap="deptResultMap" > select dept_id, dept_name from dept where dept_id=#{deptId} </select>
修改DeptDaoImpl.java,添加selectOne方法:
public Dept selectOne(int deptId){ Dept dept=null; try { session=MyBatisUtil.getSession(); dept=(Dept)session.selectOne("cn.it.entity.DeptMapper.selectOne",deptId); System.out.println("dept:"+dept); } catch (Exception e) { e.printStackTrace(); }finally{ MyBatisUtil.closeSession(); } return dept; }
2.3.5 查询操作(返回多条记录)
修改配置文件deptMapper.xml,添加
<!-- 返回多条记录,返回结果配置的不是集合类型,而是集合元素的类型;参数也可以通过Map等方式封装 --> <select id="selectList" parameterType="Map" resultMap="deptResultMap"> select * from dept where dept_name like #{deptName} </select>
修改DeptDaoImpl.java,添加selectList方法:
public List<Dept> selectList(Map map){ List<Dept> depts=null; try { session=MyBatisUtil.getSession(); depts=session.selectList("cn.it.entity.DeptMapper.selectList",map); } catch (Exception e) { e.printStackTrace(); }finally{ MyBatisUtil.closeSession(); } return depts; }
测试类代码:
@Test public void testSelectList() { Map map=new HashMap(); map.put("deptName", "%研%"); List<Dept> depts=deptDaoImpl.selectList(map); for(Dept dept:depts){ System.out.println("dept:"+dept); } }
3.动态SQL操作
3.1 准备工作
创建表及库,实体类,配置文件(参考上章节内容),以下为建表和库的SQL:
drop database if exists mybatis; create database mybatis CHARACTER SET UTF8; use mybatis; create table dept( dept_id int primary key auto_increment, dept_name varchar(50), dept_address varchar(50) ); insert into dept(dept_name,dept_address) values('研发部一部','广州'); insert into dept(dept_name,dept_address) values('研发部二部','广州'); insert into dept(dept_name,dept_address) values('研发部三部','深圳'); select * from dept;
3.2 IF语句
修改配置文件deptMapper.xml,添加
<!-- 动态IF条件 --> <select id="selectListUseIf" parameterType="Dept" resultMap="deptResultMap"> select * from dept where 1=1 <if test="deptId!=null"> and dept_id=#{deptId} </if> <if test="deptName!=null"> and dept_name=#{deptName} </if> <if test="deptAddress!=null"> and dept_address=#{deptAddress} </if> </select>
修改DeptDaoImpl.java,添加selectListUseIf方法:
//根据参数使用配置文件的IF语句自动填充查询的过滤条件 public List<Dept> selectListUseIf(Dept dept){ List<Dept> depts=null; try { session=MyBatisUtil.getSession(); depts=session.selectList("cn.it.entity.DeptMapper.selectListUseIf",dept); } catch (Exception e) { e.printStackTrace(); }finally{ MyBatisUtil.closeSession(); } return depts; }
3.3 WHERE语句
修改配置文件deptMapper.xml,添加
<!-- 动态Where条件 ,一般也需要与if结合使用,与纯if比较,省略了where 1=1--> <select id="selectListUseWhere" parameterType="Dept" resultMap="deptResultMap"> select * from dept <where> <if test="deptId!=null"> and dept_id=#{deptId} </if> <if test="deptName!=null"> and dept_name=#{deptName} </if> <if test="deptAddress!=null"> and dept_address=#{deptAddress} </if> </where> </select>
3.4 choose(when,otherwise)语句
修改配置文件deptMapper.xml,添加
<!-- 动态choose条件 ,如下配置,可以完成没有选择条件时,查找不出任何数据 --> <select id="selectListUseChoose" parameterType="Dept" resultMap="deptResultMap"> select * from dept where 1=1 <choose> <when test="deptId!=null">and dept_id=#{deptId}</when> <when test="deptName!=null">and dept_name=#{deptName}</when> <when test="deptAddress!=null">and dept_address=#{deptAddress}</when> <otherwise>and !1 = 1</otherwise> </choose> </select>
3.5 SET语句
修改配置文件deptMapper.xml,添加
<!--动态set语句可以用来更新数据 --> <update id="updateUseSet" parameterType="Dept"> update dept <set> <if test="deptName!=null">dept_name=#{deptName},</if> <if test="deptAddress!=null">dept_address=#{deptAddress},</if> </set> where dept_id=#{deptId} </update>
3.6 ForEach语句
修改配置文件deptMapper.xml,添加
< <!-- 定义根据多个部门ID查询部门相关部门信息的SQL语句 ,resultMap的值是指集合里元素的类型,parameterType不用指定 --> <select id="selectListUseForeach" parameterType="Integer[]" resultMap="deptResultMap"> select * from dept where dept_id in <!-- collection="array或list",array用来对应参数为数组,list对应参数为 集合 --> <foreach collection="array" item="deptId" open="(" separator="," close=")"> #{deptId} </foreach> </select>
3.7 include语句
修改配置文件deptMapper.xml,添加
<!-- 使用include语句动态插入表的字段及对应的值 --> <sql id="key"> <!--suffixOverrides="," 可以忽略最后“,”号 --> <trim suffixOverrides=","> <if test="deptName!=null"> dept_name, </if> <if test="deptAddress!=null"> dept_address, </if> </trim> </sql> <sql id="value"> <trim suffixOverrides="," > <if test="deptName!=null"> #{deptName}, </if> <if test="deptAddress!=null"> #{deptAddress}, </if> </trim> </sql> <insert id="insertUseInclude" parameterType="Dept"> insert into dept( <include refid="key" /> ) values( <include refid="value"/> ) </insert>