1 MyBatis简介 1.1 MyBaties MyBaties 是一个优秀的持久层框架。它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花精力处理例如注册驱动、创建connection、创建statemen手动设置参数、结果集检索等jdbc繁杂的过程代码。
MyBaties 通过 xml 或注解的方式将要执行的各种 statement(statement、prepareStatement、CallableStatement)配置起来。并通过 java 对象和 statement 中的 SQL 进行映射生成最终执行的 SQL 语句,最后由 MyBatis 框架执行 SQL 并将节果映射成 java 对象并返回。
使用ORM思想实现对象关系映射。也就是实体类中的属性 和数据库表的字段 名保持一致。
1.2 MyBatis 的框架核心
MyBatis 配置文件,包括 MyBatis 全局配置文件和 MyBatis 映射文件 ,其中全局配置文件配置了数据源、事务等信息,映射文件配置了SQL执行相关的信息。
MyBatis 通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory ,即会话工厂。
通过 SqlSessionFactory,可以创建 SqlSession 即会话。Mybatis 是通过 SqlSession 来操作数据库的。
SqlSession 本身并不能直接操作数据库,它是通过底层的 Executor 执行器接口来操作数据库的。Executor 接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认) 。
Executor 执行器要处理的 SQL 信息是封装到一个底层对象 MappedStatement 中。该对象包括:SQL语句、输入参数映射信息、输出就过集映射信息。曲中输入参数和输出节果的映射类型包括 Java的简单类型、HashMap集合对象、POJO对象类型 。
2 MyBatis 开始 2.1 开发步骤
创建maven工程并导入目标。
创建实体类和dao接口。
创建MyBatis的主配置文件 SqlMapConfig.xml。
创建映射配置文件 IUserDao.xml。
创建POJO类 1 2 3 4 5 6 7 8 public class User implements Serializable { private int id; private String username; private String sex; private Date birthday; private String address; }
创建dao层 1 2 3 4 5 6 7 package cn.Retur0.dao;import cn.Retur0.domain.User;import java.util.List;public interface IUserDao { List<User> findAll () ; }
创建全局配置文件SqlMapConfig.xml 在src下,创建 SqlMapConfig.xml 文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?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 ="mysql" > <environment id ="mysql" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/mbdemo" /> <property name ="username" value ="root" /> <property name ="password" value ="password" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="cn/Retur0/dao/IUserDao.xml" /> </mappers > </configuration >
为单个dao创建配置文件IUserDao.xml 1 2 3 4 5 6 7 8 9 10 <?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.Retur0.dao.IUserDao" > <select id ="findAll" resultType ="cn.Retur0.domain.User" > select * from user </select > </mapper >
2.2 注意事项
IUserDao.xml 也可以起名为 IUserMapper.xml。
映射文件必须与接口文件目录结构相同。
映射配置文件的 mapper 标签 namesapce 属性的取值必须是 dao 接口的全限定类名。
映射配置文件的操作配置(select 标签),id属性的取值为 dao 中的方法名。
遵从2 3 4 点之后,在开发中就不需要写 dao 的实现类了。
2.3 运行 test.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package cn.Retur0;import cn.Retur0.dao.IUserDao;import cn.Retur0.domain.User;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 java.io.InputStream;import java.util.List;public class test { public static void main (String[] args) throws Exception { InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml" ); SqlSessionFactoryBuilder bulider = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = bulider.build(in); SqlSession session = factory.openSession(); IUserDao userDao = session.getMapper(IUserDao.class ) ; List<User> users = userDao.findAll(); for (User user : users){ System.out.println(user); } session.close(); in.close(); } }
2.4 使用注解 在 dao 接口的查找方法上添加@Select注解,删除映射配置文件,并在主配置文件中改mapper为:
1 <mapper class ="cn.Retur0.dao.IUserDao" />
3 使用 MyBatis 的步骤解析 读取配置文件 1 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
此时传入的是路径。由于开发和部署环境的路径会变化,这里路径不写相对路径和绝对路径。常用的方法是:
类加载器。它只能读取类路径配置文件。
使用 ServletContext 对象的 getRealPath() 方法。
创建SqlSessionFactory工厂 1 2 SqlSessionFactoryBuilder bulider = new SqlSessionFactoryBuilder(); // 构建者 SqlSessionFactory factory = bulider.build(in);
创建工厂 mybatis 使用了构建者模式。构建者是对创建工厂类细节的封装,只需要给 builder 创建工厂类需要的信息(在 SqlMapConfig.xml 中),builder就可以给出工厂类对象。
使用工厂创建SqlSession对象 1 SqlSession session = factory.openSession();
这里使用了工厂模式。使用工厂模式的优势:解耦,降低类之间的依赖。
使用SqlSession创建Dao接口的代理对象 1 userDao = session.getMapper(IUserDao.class);
创建 Dao 实现类使用了代理模式,可以在不修改源码的基础上对方法增强。
使用代理对象执行方法 1 2 3 4 List<User> users = userDao.findAll(); for(User user : users){ System.out.println(user); }
释放资源 1 2 session.close(); in.close();
执行 findAll() 的分析 整个查询过程,我们需要的提供的信息有:
连接信息。
映射信息:
创建代理对象的分析 Spring中的Proxy。
4 Mybatis 中的 CRUD 操作 IUserDao.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package cn.Retur0.dao;import cn.Retur0.domain.User;import java.util.List;public interface IUserDao { List<User> findAll () ; void saveUser (User user) ; void updateUser (User user) ; void deleteUser (int id) ; User findById (int id) ; List<User> findByName (String username) ; int findTotal () ; }
IUserDao.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <?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.Retur0.dao.IUserDao" > <select id ="findAll" resultType ="cn.Retur0.domain.User" > select * from user </select > <insert id ="saveUser" parameterType ="cn.Retur0.domain.User" > <selectKey keyProperty ="id" keyColumn ="id" resultType ="int" order ="AFTER" > select last_insert_id(); </selectKey > insert into user(username, address, sex, birthday) values(#{username}, #{address}, #{sex}, #{birthday}); </insert > <update id ="updateUser" parameterType ="cn.Retur0.domain.User" > update user set username=#{username}, address=#{address}, sex=#{sex}, birthday=#{birthday} where id=#{id} </update > <delete id ="deleteUser" parameterType ="int" > delete from user where id=#{uid}; </delete > <select id ="findById" parameterType ="int" resultType ="cn.Retur0.domain.User" > select * from user where id=#{uid}; </select > <select id ="findByName" parameterType ="String" resultType ="cn.Retur0.domain.User" > select * from user where username like #{name} </select > <select id ="findTotal" resultType ="int" > select count(id) from user </select > </mapper >
test.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 package cn.Retur0;import cn.Retur0.dao.IUserDao;import cn.Retur0.domain.User;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 org.junit.Test;import java.io.InputStream;import java.util.Date;import java.util.List;public class test { private InputStream in; private SqlSession session; private IUserDao userDao; public void init () throws Exception { in = Resources.getResourceAsStream("SqlMapConfig.xml" ); SqlSessionFactoryBuilder bulider = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = bulider.build(in); session = factory.openSession(); userDao = session.getMapper(IUserDao.class ) ; } public void destory () throws Exception { session.commit(); in.close(); session.close(); } @Test public void t_findAll () throws Exception { init(); List<User> users = userDao.findAll(); for (User user : users){ System.out.println(user); } destory(); } @Test public void t_saveUser () throws Exception { User user = new User(); user.setUsername("saveuser" ); user.setAddress(("1-1-1" )); user.setSex("男" ); user.setBirthday(new Date()); init(); userDao.saveUser(user); System.out.println(user.getId()); destory(); } @Test public void t_updateUser () throws Exception { User user = new User(); user.setId(4 ); user.setUsername("updateuser" ); user.setAddress(("2-1-1" )); user.setSex("女" ); user.setBirthday(new Date()); init(); userDao.updateUser(user); destory(); } @Test public void t_deleteUser () throws Exception { init(); userDao.deleteUser(6 ); destory(); } @Test public void t_findById () throws Exception { init(); User u = userDao.findById(1 ); System.out.println(u.getUsername()); destory(); } @Test public void t_findByName () throws Exception { init(); List<User> users = userDao.findByName("name%" ); for (User user : users){ System.out.println(user.getUsername()); } destory(); } @Test public void t_findTotal () throws Exception { init(); int tol = userDao.findTotal(); System.out.println(tol); destory(); } }
4.1 parameterType
4.2 resultMap 当数据库中字段和 pojo 中属性名不相同时,我们需要在映射文件 IUserDao.xml 中添加resultMap 标签。
1 2 3 4 5 6 7 8 9 <resultMap id ="userMap" type ="cn.Retur0.domain.User" > <id property ="userId" column ="id" > </id > <result property ="userName" cloumn ="username" > </result > <result property ="userAddress" cloumn ="address" > </result > <result property ="userSex" cloumn ="sex" > </result > <result property ="userBirthday" cloumn ="birthday" > </result > </resultMap >
这个标签中的信息是属性名与列名的对应关系。
之后再配置 SQL 语句,标签中就不写 resultType 属性了,写 resultMap 属性,值为上面配置的 resultMap 标签的 id 属性值。这样,Mybatis 便知道实体类的属性名该如何与数据库中的类名对应。