Mybatis(iBatis)简介:
(前身为iBatis)MyBatis是一个可以自定义SQL,存储过程和高级映射的持久层框架。MyBatis消除了几乎所以是JDBC代码和参数的手工设置以及结果集的检索。MyBatis可以使用简单的XML或注解用于配制和原始映射,将接口和JavaPOJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
作用:封装了JDBC操作,简化了数据库的访问
功能如下:——封装了获取连接,执行SQL,释放连接
——封装了SQL参数设置
——封装了记录映射成实体对象的过程,实体类的属性名与结果查询结果集ResultSet中列名保持一致
开发者:写SQL和实体类,然后使用SqlSession对象执行sql操作
MyBatis体系结构主要由以下几个关键部分
(1)加载配置
配置有两种形式,一种是XML配置文件,另一种是Java代码的注解。MyBatis将SQL的配置信息加载成为一个个MappdStatement对象(
包括了传入参数映射配置,执行的SQL语句,结果映射配置),并将其存储在内存中。
(2)SQL解析
当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map,JavaBean或者基本数据类型)MyBatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。
(3)SQL执行
将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果
(4)结果映射
将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap,JavaBean或者数据类型,并将最终结果返回。
MyBatis配置文件
MyBatis框架的XML配置文件包含以下两种类型
(1)SqlMapConfig.xml(1个)
主配置文件,用于指定数据库连接参数和框架参数
(2)SqlMap.xml(n个)
映射定义文件,用于定义SQL语句和映射信息
MyBatis框架API
在使用MyBatis框架时,主要涉及以下几个API
(1)SqlSessionFactoryBuilder
该对象负责根据MyBatis配置文件SqlMapConfig.xml构建SqlSessionFactory实例
(2)SqlSessionFactory
每一个MyBatis的应用程序都以一个SqlSessionFactory对象为核心。该对象负责创建SqlSession对象实例
(3)SqlSession
该对象包含了所以执行SQL操作的方法,用于执行已映射的SQL语句
MyBatis主要流程结构:
1.在使用MyBatis之前,需要将MyBatis框架添加到工程中,主要步骤如下:
1)为工程添加MyBatis开发包和数据库驱动包
2)在src下添加MyBatis配置文件SqlMapConfig.xml
3)修改SqlMapConfig.xml,指定数据库连接参数
4)利用MyBatis API编程,获取SqlSession实例
2.当获取SqlSession对象后,就可以利用它对数据表执行增删改查操作了,使用步骤如下:
1)根据数据表编写实体类(Java POJO)
2)编写SqlMap.xml映射文件,定义SQL操作和映射信息
3)获取SqlSession对象,执行增删改查操作
4)提交事务(DML操作)
5)释放SqlSession对象资源
具体操作:
(1)SqlMapConfig.xml(指定数据库连接参数和SQL定义文件)
<?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="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql:///jsd1507db?useUnicode=true&characterEncoding=utf-8" /> <property name="username" value="system" /> <property name="password" value="wyt000000" /> </dataSource> </environment> </environments> <mappers> <!-- 声明所有的mapper.xml --> <mapper resource="org/web/entity/EmpMapper.xml" /> </mappers> </configuration>
(2)引入jar包(驱动包.mybatis包)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.web</groupId> <artifactId>springMyBatis</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>springMyBatis Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <!-- 添加jstl依赖 --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <!-- Spring依赖包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!-- mybatis依赖包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.8</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <!-- mysqly依赖包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!-- 阿里巴巴数据源的jar包依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.18</version> </dependency> </dependencies> <build> <finalName>springMyBatis</finalName> <pluginManagement> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat6-maven-plugin</artifactId> <version>2.3-SNAPSHOT</version> </plugin> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.3-SNAPSHOT</version> </plugin> </plugins> </pluginManagement> </build> </project>
(3)编写实体类(要求属性名与数据表中字段名保持一致) 如:Emp
package org.web.entity; import java.io.Serializable; public class Emp implements Serializable{ //属性名与emp表字段一致 private Integer id; private String name; private Double salary; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
(4)编写SQL.xml(定义sql) 实现增删改查 如:EmpMapper.xml
<?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"> <!-- resultType:查询结果的返回类型,映射对象类型 --> <mapper namespace="empsql"> <select id="findAll" resultType="org.web.entity.Emp"> select * from emp </select> <!-- parameterType:传入参数的类型 例如name的类型为string --> <select id="findLikeName" parameterType="string" resultType="org.web.entity.Emp"> select * from emp where name like #{name} </select> <select id="findById" parameterType="int" resultType="org.web.entity.Emp"> select * from emp where id=#{id} </select> <insert id="save" parameterType="org.web.entity.Emp"> insert into emp (name,salary,age) values (#{name},#{salary},#{sag}) </insert> <!-- session.delete(id,16) --> <delete id="delete" parameterType="int"> delete from emp where id=#{eid} </delete> <!-- session.update(id,emp) --> <update id="updateSalary" parameterType="org.web.entity.Emp"> update emp set salary=#{salary} where id=#{id} </update> </mapper>
(5)获取SqlSession对象
package test; import java.io.InputStream; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MyBatisUtil { public static SqlSession getSqlSession(){ SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); //加载SqlMapConfig.xml String conf="SqlMapConfig.xml"; //将文件变为流 InputStream confStream=MyBatisUtil.class.getClassLoader().getResourceAsStream(conf); //获取SqlsessionFactory SqlSessionFactory factory=builder.build(confStream); //获取SqlSession SqlSession session=factory.openSession(); return session; } }
(6)测试如下:
package test; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.List; 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.web.entity.Emp; public class Testemp { public static void main(String[] args) throws IOException { SqlSession session=MyBatisUtil.getSqlSession(); //测试多行查询 //list集合的形式返回查询的数据 //List<Emp> list=session.selectList("findAll"); //自动封装为Emp类型 List<Emp> list=session.selectList("findLikeName","%张%"); for(Emp e:list){ System.out.println(e.getName()); } //测试单行查询 Emp emp=session.selectOne("findById",18); if(emp!=null){ System.out.println(emp.getName()); }else{ System.out.println("未查询到记录"); } //测试添加,不会自动提交事务,需要commit一下 Emp emp1=new Emp(); emp1.setName("scott"); emp1.setSalary(5000.0); emp1.setAge(20); session.insert("save",emp1); session.commit();//提交事务,增删改操作必须做事务提交 //测试更新工资、 Emp emp2=new Emp(); emp2.setId(20); emp2.setSalary(8000.0); session.update("updateSalary",emp2); session.commit(); //提交事务,增删改操作必须做事务提交 session.close(); } }
使用MyBatis返回的数据类型:
(1)实体对象:
实体类:
package org.web.entity; import java.io.Serializable; import java.util.Date; public class Cost implements Serializable{ private int cost_id; private String name; private int base_duration; private int base_cost; private int unit_cost; private String status; private String descr; private Date creatime; private Date startime; public int getCost_id() { return cost_id; } public void setCost_id(int cost_id) { this.cost_id = cost_id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getBase_duration() { return base_duration; } public void setBase_duration(int base_duration) { this.base_duration = base_duration; } public int getBase_cost() { return base_cost; } public void setBase_cost(int base_cost) { this.base_cost = base_cost; } public int getUnit_cost() { return unit_cost; } public void setUnit_cost(int unit_cost) { this.unit_cost = unit_cost; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public String getDescr() { return descr; } public void setDescr(String descr) { this.descr = descr; } public Date getCreatime() { return creatime; } public void setCreatime(Date creatime) { this.creatime = creatime; } public Date getStartime() { return startime; } public void setStartime(Date startime) { this.startime = startime; } public String getCost_type() { return cost_type; } public void setCost_type(String cost_type) { this.cost_type = cost_type; } private String cost_type; }
1)当实体类属性名与字段名一致时,使用resultType
<?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"> <!-- resultType:查询结果的返回类型,映射对象类型 --> <mapper namespace="org.web.dao.CostDao"> <select id="findCost" resultType="org.web.entity.CostBean1"> select cost_id,name,status,creatime from cost </select> </mapper>
2)当属性名与字段名不一致时:给字段使用别名,使它与属性名一致,使用resultMap代替resultType定义如何装载数据
需要使用<resultMap>元素显示指定映射关系。
<?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"> <!-- resultType:查询结果的返回类型,映射对象类型 --> <mapper namespace="org.web.dao.CostDao"> <!-- resultType:默认按照名称匹配装载数据 --> <!-- resultMap属性(自定义):按照指定定义规则装载数据--> <!-- 当属性名誉字段名不一致时,使用别名 --> <select id="findCost" resultMap="costMap"> select cost_id,name,status,creatime from cost </select> <resultMap type="org.web.entity.CostBean1" id="costMap"> <!-- 主键字段定义 --> <id property="id" column="cost_id"/> <!-- 非主键字段定义 --> <result property="name" column="name"/> <result property="status" column="status"/> <result property="createTime" column="createTime"/> </resultMap> </mapper>
(2)Map集合
<?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"> <!-- resultType:查询结果的返回类型,映射对象类型 --> <mapper namespace="org.web.dao.CostDao"> <!-- 查询字段较少时,最好选择map封装 --> <select id="findMap" resultType="map"> select cost_id,name from cost </select> </mapper>
测试:
package test; import java.util.List; import java.util.Map; import org.apache.ibatis.session.SqlSession; import org.web.dao.CostDao; import org.web.entity.Cost; import org.web.entity.CostBean1; import org.web.util.MyBatisUtil; public class TestCost { public static void main(String[] args) { SqlSession session=MyBatisUtil.getSession(); //测试返回Map结果 List<Map<String,Object>> list2=session.selectList("findMap"); for(Map<String,Object> data:list2){ System.out.println(data.get("cost_id")+" "+data.get("name")); } session.close(); } }
(3)基本值
<?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"> <!-- resultType:查询结果的返回类型,映射对象类型 --> <mapper namespace="org.web.dao.CostDao"> <select id="findRows" resultType="int"> select count(*) from cost </select> </mapper>
测试:
package test; import java.util.List; import java.util.Map; import org.apache.ibatis.session.SqlSession; import org.web.dao.CostDao; import org.web.entity.Cost; import org.web.entity.CostBean1; import org.web.util.MyBatisUtil; public class TestCost { public static void main(String[] args) { SqlSession session=MyBatisUtil.getSession(); //测试返回单个值 int rows=session.selectOne("findRows"); System.out.println("记录数"+rows); }
使用Mapper映射器
Mapper映射器是开发者创建绑定映射语句的借口,映射接口的实例可以从SqlSession中获得
SqlSession session=sqlSessionFactory.openSession(); try{ CostDao mapper=session.getMapper(CostDao.class) }finally{ session.close(); }
CostMapper接口定义如下:
package org.web.dao; import java.util.List; import java.util.Map; import org.apache.ibatis.session.SqlSession; import org.web.entity.Cost; import org.web.util.MyBatisUtil; //定义映射接口,不需要写实现类,会在内存中动态自动构建 public interface CostDao { public List<Cost> findAll(); public List<Cost> findPage(int begin); public List<Map<String,Object>> findMap(); public int findRows(); }
Mapper映射器接口规则
1)根据SQL定义的id属性当接口方法名
2)根据SQL定义的parameterType类型当方法参数
3)根据SQL定义的resultType类型当方法的返回类型:多行使用List<泛型>;单行使用 泛型;
4)将SQL定义文件<mapper>的namespace属性指定成"包名.接口名"