MyBatis是轻量级的数据库访问API,封装了JDBC操作,可以实现对实体对象的CRUD操作。
MyBatis体系结构主要组成部分:
配置文件:SqlMapConfig.xml 主配置文件
声明了数据库连接参数,引用了映射文件
映射文件: 每个实体一个映射文件
映射文件与 Mapper接口对应。
映射文件中:
每个Mapper接口中的方法,对应映射文件中的SQL语句。
使用步骤:
使用MyBatis
1 导入包
2 创建配置文件
3 创建实体和Mapper接口,已经映射文件
4 使用 工厂创建SqlSession
5 创建Mapper接口对象,执行接口方法
下面来详细介绍。
1),加载配置
两钟形式,一种是XML配置文件,另一种是JAVA代码的注解。
MyBatis将SQL的配置信息加载成为一个个的MappedStatement对象(包括了传入参数映射配置,执行的SQL语句,结果映射配置),并将其存储在内存中。
A)SqlMapConfig.xml
只有一个,用于配置数据库连接参数和框架参数。
<?xml version="1.0" encoding="UTF-8" ?> <!--这段代码不能掉,否则出现异常--> <!DOCTYPE configuration PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-config.dtd"> <configuration> <!--配置数据库连接 --> <environments default="environment"> <environment id="environment"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="oracle.jdbc.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@localhost:1521:XE" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> <!-- 引入 Dept.xml 配置 --> <mappers> <mapper resource="com/lydia/entity/Dept.xml"/> </mappers> </configuration>
B) 实体类对应的映射文件
Dept.xml ,该配置文件是映射Dept.java实体类的
<!-- Dept.xml 在com.lydia.entity 包中 --> <!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> <!-- namespace 的值是 DeptMapper 接口 每个Mapper 接口对应一个配置文件 --> <mapper namespace="com.lydia.entity.DeptMapper"> <!--此处的DeptMapper是我们封装的接口--> <insert id="addDept" parameterType="com.lydia.entity.Dept"> <selectKey keyProperty="deptno" order="BEFORE" resultType="int"> select SEQ_T_DEPT.nextval from DUAL </selectKey> insert into T_DEPT (deptno, dname, loc) values (#{deptno}, #{dname}, #{loc}) </insert> <delete id="deleteDept" parameterType="com.lydia.entity.Dept"> delete from T_DEPT where deptno = #{deptno} </delete> <select id="findDeptById" parameterType="java.lang.Integer" resultType="com.lydia.entity.Dept"> select deptno,dname,loc from T_DEPT where deptno=#{deptno} </select> <update id="updateDept" parameterType="com.lydia.entity.Dept"> <!-- #{deptno} 读取参数的Bean属性 --> update T_DEPT set dname=#{dname}, loc = #{loc} where deptno=#{deptno} </update> <!-- 注意resultType 的值是List中元素类型 结果集行映射的数据类型--> <select id="findAllDept" resultType="com.lydia.entity.Dept"> select deptno, dname, loc from T_DEPT </select> <select id="findDeptByLoc" parameterType="java.lang.String" resultType="com.lydia.entity.Dept"> select deptno, dname, loc from T_DEPT where loc=#{loc} </select> <select id="findAllDname" parameterType="java.lang.String" resultType="java.util.Map"> select dname from T_DEPT where loc=#{loc} </select> </mapper>
注意:这里特别要注意主键ID的处理。
本案例中使用Oracle,那么要先创建序列 CREATE SEQUENCE SEQ_T_DEPT; 然后使用<select-key>..
如果是MySQL 或者 DB2,主键ID是自动增长的,可以如下设置:
<!-- 自增类型(MySql SqlServer DB2 Derby)--> <insert id="addDept" useGeneratedKeys="true" keyProperty="deptno" parameterType="com.tarean.entity.Dept"> insert into T_DEPT(dname, loc) values (#{dname},#{loc}) </insert>
2),SQL解析
当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map,JavaBean,基本数据类型))。MyBatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析。解析后可以得到最终要执行的SQL和参数。
3),结果映射
将操作数据库的结果按照映射的配置进行转换。可以转换成HashMap,JavaBean或者基本数据类型,并最终将结果返回。
创建DeptMapper.java接口,该接口中封装了Dept.xml中指定的SQL方法。
/** * Mapper接口,类似于Dao,但是语法有限定 * 不能有重载 * Mapper 定义实体Dept对象的CRUD操作 *该类中的方法名必须和Dept.xml中SQL的id一致 */
public interface DeptMapper { void addDept(Dept dept); void deleteDept(Dept dept); void updateDept(Dept dept); Dept findDeptById(Integer deptno); List<Dept> findAllDept(); List<Dept> findDeptByLoc(String loc); List<Map<String, Object>> findAllDname( String loc); }
MyBatis框架中设计到的几个API
SqlSessionFactoryBuilder
--该对象负责根据MyBatis配置文件SqlMapConfig.xml构建SqlSessionFactory实例
SqlSessionFactory
--每一个MyBatis的应用程序都以一个SqlSessionFactory对象为核心。该对象负责创建SqlSession对象实例。
SqlSession
--该对象包含了所有执行SQL操作的方法,用于执行已映射的SQL语句
TestCass.java类负责调用MyBatis中的基本API来操作数据库。
package com.lydia.test; import java.io.Reader; import java.sql.Connection; import java.util.List; import java.util.Map; 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 com.lydia.entity.Dept; import com.lydia.entity.DeptMapper; public class TestCase { // @Test public void testSqlSession() throws Exception { String cfg = "SqlMapConfig.xml"; Reader reader = Resources.getResourceAsReader(cfg); //创建builder对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(reader); //创建session SqlSession session = factory.openSession(); Connection conn = session.getConnection(); System.out.println(conn); System.out.println(conn.getMetaData().getDatabaseProductName()); conn.close(); session.close(); } @Test public void testAddDept() throws Exception { String cfg = "SqlMapConfig.xml"; Reader reader = Resources.getResourceAsReader(cfg); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(reader); SqlSession session = factory.openSession(); // +++++++++++++++++++++++++++++++++++++++ // 通过Mapper映射器去执行SQL // DeptMapper mapper = // session.getMapper(DeptMapper.class); // Dept dept = new Dept("C++","武汉"); // mapper.addDept(dept); // System.out.println(dept); // +++++++++++++++++++++++++++++++++++++++ // 通过session去执行SQL Dept dept = new Dept("C++", "武汉"); session.insert("addDept", dept); // +++++++++++++++++++++++++++++++++++++++ session.commit(); session.close(); } // @Test public void testDelete() throws Exception { String cfg = "SqlMapConfig.xml"; Reader reader = Resources.getResourceAsReader(cfg); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(reader); SqlSession session = factory.openSession(); DeptMapper mapper = session.getMapper(DeptMapper.class); Dept dept = mapper.findDeptById(2); mapper.deleteDept(dept); System.out.println(dept); Dept d = mapper.findDeptById(2); System.out.println(d); session.commit(); session.close(); } @Test public void testFindAll() throws Exception { String cfg = "SqlMapConfig.xml"; Reader reader = Resources.getResourceAsReader(cfg); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(reader); SqlSession session = factory.openSession(); DeptMapper mapper = session.getMapper(DeptMapper.class); List<Dept> list = mapper.findAllDept(); for (Dept dept : list) { System.out.println(dept); } session.close(); } // @Test public void testUpdate() throws Exception { String cfg = "SqlMapConfig.xml"; Reader reader = Resources.getResourceAsReader(cfg); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(reader); SqlSession session = factory.openSession(); DeptMapper mapper = session.getMapper(DeptMapper.class); Dept d = mapper.findDeptById(4); d.setDname("PHP"); d.setLoc("苏州桥"); mapper.updateDept(d); List<Dept> list = mapper.findAllDept(); for (Dept dept : list) { System.out.println(dept); } session.commit(); session.close(); } // @Test public void testMap() throws Exception { String cfg = "SqlMapConfig.xml"; Reader reader = Resources.getResourceAsReader(cfg); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(reader); SqlSession session = factory.openSession(); DeptMapper mapper = session.getMapper(DeptMapper.class); List<Map<String, Object>> list = mapper.findAllDname("苏州桥"); System.out.println(list); session.close(); } @Test public void testPage() throws Exception { String cfg = "SqlMapConfig.xml"; SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); Reader reader = Resources.getResourceAsReader(cfg); SqlSessionFactory factory = builder.build(reader); SqlSession session = factory.openSession(); //+++++++++++++++++++++++++++++++++++++ RowBounds bounds = new RowBounds(0, 2); //此处用的selectList(arg1,arg2,arg3); 中间arg2参数不要掉 List<Dept> list = session.selectList("findAllDept",null, bounds); for (Dept dept : list) { System.out.println(dept); } session.commit(); session.close(); //+++++++++++++++++++++++++++++++++++++ } }
注意:上面调用CRUD的操作方法也可以使用以下的代替
String cfg = "SqlMapConfig.xml"; Reader reader = Resources.getResourceAsReader(cfg); SqlSessionFactoryBuilder builder= new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(reader); SqlSession session = factory.openSession(); Dept dept = new Dept("C++","武汉"); session.insert("addDept", dept); session.commit(); session.close();
ResultMap映射定义:
在Dept.xml中定义<select>操作时,如果查询结果字段名和javaBean属性不一致,需要使用<resultMap>元素显示指定映射关系。例如Dept.java中的属性是 no,name,loc,那么应该如下配置:
<select id ="findAll2" resultMap="deptMap"> select DEPTNO,DNAME,LOC from DEPT </select> <resultMap id = "deptMap" type="com.lydia.Dept"> <result property="no" column="deptno"/> <result property="name" column="dname"/> <result property="loc" column="loc"/> </resultMap>