MyBatis(国税)
目录
一、MyBatis 概要
1.1、ORM 介绍
对象关系映射(Object Relational Mapping,简称 ORM,或 O/RM,或 O/R mapping),用于实现面向对象编程语言里不同类型系统的数据之间的转换。它是创建了一个可在编程语言里使用的“虚拟对象数据库”。简单来说 ORM 简化了应用程序对数据库的访问,实现了将数据库中的数据与程序中的对象进行相互映射,数据库中的一行记录可以对应一个对象,一个强类型的集合可以对应一张表。
1.2、常见的 ORM 框架与库
自己定义的 JDBCUtil 缺点:没有数据库连接池,影响性能;功能简单,不能应对复杂需求;没有缓存机制;
DBUtils:Commons DbUtils 是 Apache 组织提供的一个对 JDBC 进行简单封装的开源工具类库,使用它能够简化 JDBC 应用程序的开发,同时也不会影响程序的性能。如果自己想学习写框架,可以从该开源项目开始。
- Hibernate:全自动 需要些 hql 语句,与 Struts、Spring 组成 SSH 的搭配
- SSH(Struts2、Spring、Hibernate) S2SH
- Struts:MVC 框架;Hibernate:ORM 框架,冬眠;Spring:IOC、AOP…
- MyBatis:半自动 自己写 sql 语句, 可操作性强, 小巧,最开始 iBatis
- JPA:(Java Persistence API) 是 Sun 官方提出的 Java 持久化规范。它为 Java 开发人员提供了一种对象 / 关系映射工具来管理 Java 应用中的关系数据。
1.3、MyBatis
MyBatis 本是 apache 的一个开源项目 iBatis, 2010 年这个项目由 apache software foundation 迁移到了 google code,并且改名为 MyBatis 。2013 年 11 月迁移到 Github,网址:https://github.com/mybatis。
iBATIS 一词来源于“internet”和“abatis”的组合,是一个基于 Java 的持久层框架。iBATIS 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAO)
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。
每个 MyBatis 应用程序主要都是使用 SqlSessionFactory 实例的,一个 SqlSessionFactory 实例可以通过 SqlSessionFactoryBuilder 获得。SqlSessionFactoryBuilder 可以从一个 xml 配置文件或者一个预定义的配置类的实例获得。
用 xml 文件构建 SqlSessionFactory 实例是非常简单的事情。推荐在这个配置中使用类路径资源(classpath resource),但你可以使用任何 Reader 实例,包括用文件路径或 file:// 开头的 url 创建的实例。MyBatis 有一个实用类 ----Resources,它有很多方法,可以方便地从类路径及其它位置加载资源。
优点:
- 1. 易于上手和掌握。
- 2. sql 写在 xml 里,便于统一管理和优化。
- 3. 解除 sql 与程序代码的耦合。
- 4. 提供映射标签,支持对象与数据库的 orm 字段关系映射
- 5. 提供对象关系映射标签,支持对象关系组建维护
- 6. 提供 xml 标签,支持编写动态 sql。
git 地址:https://github.com/mybatis/
下载源码:https://github.com/mybatis/mybatis-3/releases
下载 Jar 包:https://github.com/mybatis/mybatis-3
官方文档:http://www.mybatis.org/mybatis-3/zh/index.html
MyBatis 是一个支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索封装。MyBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。
二、MyBatis 示例
2.1、MyBatis 基础
结果:
添加包
mybatis.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"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> <property name="username" value="tax"/> <property name="password" value="orcl"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/tax/mapping/bookMapping.xml"/> </mappers> </configuration>
Book.java POJO 对象
package com.tax.model;/图书实体 Bean POJO*/
public class Book {
/编号/
private int id;
/**书名/
private String title;
/类型*/
private String typename;
/价格/
private Double price;
/**状态/
private String state;@Override </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String toString() { </span><span style="color: rgba(0, 0, 255, 1)">return</span> "Book{" + "id=" + id + ", title='" + title + '\'' + ", typename='" + typename + '\'' + ", price=" + price + ", state='" + state + '\'' + '}'<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getId() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setId(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getTitle() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> title; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setTitle(String title) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.title =<span style="color: rgba(0, 0, 0, 1)"> title; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getTypename() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> typename; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setTypename(String typename) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.typename =<span style="color: rgba(0, 0, 0, 1)"> typename; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Double getPrice() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> price; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setPrice(Double price) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.price =<span style="color: rgba(0, 0, 0, 1)"> price; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getState() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> state; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setState(String state) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.state =<span style="color: rgba(0, 0, 0, 1)"> state; }
}
bookMaping.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="com.tax.mapping.bookMapper"> <!-- 根据 id 查询得到一个 book 对象 --> <select id="getBookById" resultType="com.tax.model.Book"> select id, title, typename, price, state from book where id=#{id} </select> <select id="getAllBooks" resultType="com.tax.model.Book"> select id, title, typename, price, state from book </select> </mapper>
BookDao 数据访问
package com.tax.dao;import com.tax.model.Book;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;
/图书数据访问*/
public class BookDao {
/获得图书通过编号*/
public Book getBookById(int id){
//将 mybatis 的配置文件转换成输入流,读配置文件
InputStream cfg=this.getClass().getClassLoader().getResourceAsStream("mybatis.xml");
//根据配置文件构建会话工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(cfg);
//创建会话
SqlSession session=factory.openSession();
//调用方法 getBookById 带入参数 1 获得单个图书对象
Book book=session.selectOne("com.tax.mapping.bookMapper.getBookById",id);
//关闭会话
session.close();
return book;
}</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) { BookDao dao</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BookDao(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">输出</span> System.out.println(dao.getBookById(3<span style="color: rgba(0, 0, 0, 1)">)); }
}
运行结果:
Book{id=3, title='Java 并发编程的艺术', typename='软件工程', price=45.4, state='未借出'}
2.2、JUnit 单元测试
添加 JUnit 依赖
添加测试的包与类
package com.tax.test;import com.tax.dao.BookDao;
import com.tax.model.Book;
import org.junit.Assert;
import org.junit.Test;
import org.junit.Assert.*;public class BookDaoTest {
@Test
public void getBookById(){
BookDao dao=new BookDao();
Book book=dao.getBookById(1);
System.out.println(book);
//断言,期待 1,实际 2
//Assert.assertEquals(1,2);
//不为空就通过
Assert.assertNotNull(book);
}}
其它注解
import static org.junit.Assert.assertEquals; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test;public class CalculatorTest {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> Calculator calculator = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Calculator(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">每个方法测试前调用</span>
@Before
public void clearCalculator() {
calculator.clear();
}</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">每个方法测试完以后调用</span>
@After
public void tearDown()
{
}</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">@Test:测试方法,表明这是一个测试方法。在Junit中将会自动被执行。</span>
@Test
public void add() {
calculator.add(1);
calculator.add(1);
//第一个参数是预期的,第二个参数是真实的
assertEquals(calculator.getResult(), 2);
}@Test </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> subtract() { calculator.add(</span>10<span style="color: rgba(0, 0, 0, 1)">); calculator.substract(</span>2<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">第一个参数是预期的,第二个参数是真实的 </span> assertEquals(calculator.getResult(), 8<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">给测试函数设定一个执行时间,超过了这个时间(400毫秒),它们就会被系统强行终止</span> @Test(timeout=400<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> divide() { calculator.add(</span>8<span style="color: rgba(0, 0, 0, 1)">); calculator.divide(</span>2<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">第一个参数是预期的,第二个参数是真实的 </span> <span style="color: rgba(0, 0, 255, 1)">assert</span> calculator.getResult() == 5<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用注释来声明该异常是预期的,异常测试是Junit4中的最大改进</span> @Test(expected = ArithmeticException.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> divideByZero() { calculator.divide(</span>0<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">@Ignore:忽略的测试方法,标注的含义就是“某些方法尚未完成,暂不参与此次测试”</span> @Ignore("not ready yet"<span style="color: rgba(0, 0, 0, 1)">) @Test </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> multiply() { calculator.add(</span>10<span style="color: rgba(0, 0, 0, 1)">); calculator.multiply(</span>10<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">第一个参数是预期的,第二个参数是真实的 </span> assertEquals(calculator.getResult(), 100<span style="color: rgba(0, 0, 0, 1)">); }
}
注解
@Test 测试方法,表明这是一个测试方法。在 Junit 中将会自动被执行。
@Test(timeOut=400) 给测试函数设定一个执行时间,超过了这个时间 (400 毫秒),它们就会被系统强行终止
@Test(expected = ArithmeticException.class) 使用注释来声明该异常是预期的,异常测试是 Junit4 中的最大改进
@Ignore("not ready yet") 忽略的测试方法,标注的含义就是“某些方法尚未完成,暂不参与此次测试”
@Before 每个方法测试前调用
@After 每个方法测试完以后调用
@BeforeClass 每个类运行前调用,并且只调用一次
@AfterClass 每个类运行后调用,并且只调用一次
2.3、XML+ 接口实现 CRUD
BookDao 接口
package com.tax.dao2;import com.tax.model.Book;
import java.util.List;
public interface BookDao {
public Book getBookById(int id);</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<Book><span style="color: rgba(0, 0, 0, 1)"> getAllBooks(); </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> add(Book book); </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> update(Book book); </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> deleteById(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id);
}
MyBatis 工具类
package com.tax.dao2;import java.io.InputStream;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;public abstract class MyBatisUtil {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">GC不理static</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> SqlSessionFactory factory=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> SqlSessionFactory getSqlSessionFactory(){ </span><span style="color: rgba(0, 0, 255, 1)">if</span>(factory==<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){ </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获得环境配置文件流</span> InputStream config = MyBatisUtil.<span style="color: rgba(0, 0, 255, 1)">class</span>.getClassLoader().getResourceAsStream("mybatis.xml"<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建sql会话工厂</span> factory = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SqlSessionFactoryBuilder().build(config); } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> factory; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获得会话</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> SqlSession getSession(){ </span><span style="color: rgba(0, 0, 255, 1)">return</span> getSqlSessionFactory().openSession(<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 获得得sql会话 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> isAutoCommit 是否自动提交,如果为false则需要sqlSession.commit();rollback(); * </span><span style="color: rgba(128, 128, 128, 1)">@return</span><span style="color: rgba(0, 128, 0, 1)"> sql会话 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> SqlSession getSession(<span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> isAutoCommit){ </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> getSqlSessionFactory().openSession(isAutoCommit); }
}
Book 表映射文件
<?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="com.tax.dao2.BookDao"> <!-- 根据 id 查询得到一个 book 对象 --> <select id="getBookById" resultType="Book"> select id, title, typename, price, state from book where id=#{id} </select><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">select </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="getAllBooks"</span><span style="color: rgba(255, 0, 0, 1)"> resultType</span><span style="color: rgba(0, 0, 255, 1)">="Book"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> select id, title, typename, price, state from book </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">select</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">insert </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="add"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="Book"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> insert into book (id, title, typename, price, state) values(seq_book_id.nextval, #{title}, #{typename}, #{price}, #{state}) </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">insert</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">update </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="update"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="Book"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> update book set title=#{title},typename=#{typename},price=#{price},state=#{state} where id=#{id} </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">update</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">delete </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="deleteById"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> delete from book where id=#{id} </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">delete</span><span style="color: rgba(0, 0, 255, 1)">></span>
</mapper>
BookDaoImpl 实现
package com.tax.dao2;import com.tax.model.Book;
import org.apache.ibatis.session.SqlSession;import java.util.List;
public class BookDaoImpl implements BookDao {
@Override
public Book getBookById(int id) {
SqlSession session = null;
try {
session = MyBatisUtil.getSession();
BookDao dao = session.getMapper(BookDao.class);
return dao.getBookById(id);
} finally {
session.close();
}
}@Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> List<Book><span style="color: rgba(0, 0, 0, 1)"> getAllBooks() { SqlSession session </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { session </span>=<span style="color: rgba(0, 0, 0, 1)"> MyBatisUtil.getSession(); BookDao dao </span>= session.getMapper(BookDao.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> dao.getAllBooks(); } </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> { session.close(); } } @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> add(Book book) { SqlSession session </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { session </span>=<span style="color: rgba(0, 0, 0, 1)"> MyBatisUtil.getSession(); BookDao dao </span>= session.getMapper(BookDao.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> dao.add(book); } </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> { session.close(); } } @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> update(Book book) { SqlSession session </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { session </span>=<span style="color: rgba(0, 0, 0, 1)"> MyBatisUtil.getSession(); BookDao dao </span>= session.getMapper(BookDao.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> dao.update(book); } </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> { session.close(); } } @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> deleteById(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) { SqlSession session </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> { session </span>=<span style="color: rgba(0, 0, 0, 1)"> MyBatisUtil.getSession(); BookDao dao </span>= session.getMapper(BookDao.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> dao.deleteById(id); } </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> { session.close(); } }
}
测试文件
package test.com.tax.dao2;import com.tax.dao2.BookDao;
import com.tax.dao2.BookDaoImpl;
import com.tax.model.Book;
import org.junit.Assert;
import org.junit.Test;
import org.junit.Before;
import org.junit.After;/**
BookDaoImpl Tester.
@author <Authors name>
@version 1.0
@since <pre>03/15/2018</pre>
*/
public class BookDaoImplTest {BookDao dao;
@Before
public void before() throws Exception {
dao = new BookDaoImpl();
}@After
public void after() throws Exception {
}/**
- Method: getBookById(int id)
*/
@Test
public void testGetBookById() throws Exception {
System.out.println(dao.getBookById(3));
}/**
- Method: getAllBooks()
*/
@Test
public void testGetAllBooks() throws Exception {
for (Book book:dao.getAllBooks()) {
System.out.println(book);
}
}/**
- Method: add(Book book)
*/
@Test
public void testAdd() throws Exception {
Book book=new Book();
book.setTypename("计算机");
book.setState("未借出");
book.setTitle("Spring 入门到放弃");
book.setPrice(23.5);
Assert.assertEquals(1,dao.add(book));
}/**
- Method: update(Book book)
*/
@Test
public void testUpdate() throws Exception {
Book book=dao.getBookById(49);
book.setTypename("从入门到精通");
Assert.assertEquals(1,dao.update(book));
}/**
- Method: deleteById(int id)
*/
@Test
public void testDeleteById() throws Exception {
Assert.assertEquals(1,dao.deleteById(49));
}}
结果:
2.4、基于注解实现 CRUD
使用注解不再需要 mapping 文件
BookDao 接口如下:
package com.tax.dao;import com.tax.model.Book;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;import java.util.List;
public interface BookDao {
@Select("select id, title, typename, price, state from book where id=#{id}")
public Book getBookById(int id);@Select(</span>"select * from book"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> List<Book><span style="color: rgba(0, 0, 0, 1)"> getAllBooks(); @Insert(</span>"insert into book (id, title, typename, price, state) values(seq_book_id.nextval, #{title}, #{typename}, #{price}, #{state})"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> add(Book book); @Update(</span>"update book set title=#{title},typename=#{typename},price=#{price},state=#{state} where id=#{id}"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> update(Book book); @Delete(</span>"delete from book where id=#{id}"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> deleteById(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id);
}
mybatis.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"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> <property name="username" value="tax"/> <property name="password" value="orcl"/> </dataSource> </environment> </environments> <mappers> <mapper class="com.tax.dao.BookDao"/> </mappers> </configuration>
其它内容与 2.3 节一样。
2.5、别名与数据源
bookMapping.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="com.tax.dao2.BookDao"> <!-- 根据 id 查询得到一个 book 对象 --> <select id="getBookById" resultType="B"> select id, title, typename, price, state from book where id=#{id} </select><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">select </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="getAllBooks"</span><span style="color: rgba(255, 0, 0, 1)"> resultType</span><span style="color: rgba(0, 0, 255, 1)">="B"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> select id, title, typename, price, state from book </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">select</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">insert </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="add"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="Book"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> insert into book (id, title, typename, price, state) values(seq_book_id.nextval, #{title}, #{typename}, #{price}, #{state}) </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">insert</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">update </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="update"</span><span style="color: rgba(255, 0, 0, 1)"> parameterType</span><span style="color: rgba(0, 0, 255, 1)">="Book"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> update book set title=#{title},typename=#{typename},price=#{price},state=#{state} where id=#{id} </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">update</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">delete </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="deleteById"</span><span style="color: rgba(0, 0, 255, 1)">></span><span style="color: rgba(0, 0, 0, 1)"> delete from book where id=#{id} </span><span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">delete</span><span style="color: rgba(0, 0, 255, 1)">></span>
</mapper>
mybatis.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> <typeAliases> <typeAlias type="com.tax.model.Book" alias="B"></typeAlias> <package name="com.tax.model"></package> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> <property name="username" value="tax"/> <property name="password" value="orcl"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/tax/mapping/bookMapping.xml"/> </mappers> </configuration>
数据源
db.properties
driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@127.0.0.1:1521:orcl username=tax password=orcl
mybatis.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> <properties resource="db.properties"></properties> <environments default="development"> <environment id="development"> <transactionManager type="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> <mappers> <mapper class="com.tax.dao.BookDao"/> </mappers> </configuration>
2.6、Java Web 中整合 MyBatis(展示与删除功能)
项目结构:
BookServlet
package com.tax.action;import com.tax.dao.BookDao;
import com.tax.dao.BookDaoImpl;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/BookServlet")
public class BookServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获得action类型</span> String act=request.getParameter("act"<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果当前的动作是删除</span> <span style="color: rgba(0, 0, 255, 1)">if</span>(act.equals("delete"<span style="color: rgba(0, 0, 0, 1)">)) { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获得URL中要删除的图书编号</span> <span style="color: rgba(0, 0, 255, 1)">int</span> id=Integer.parseInt(request.getParameter("id"<span style="color: rgba(0, 0, 0, 1)">)); BookDao dao</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BookDaoImpl(); </span><span style="color: rgba(0, 0, 255, 1)">if</span>(dao.deleteById(id)>0){ <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">执行删除并成功</span> request.setAttribute("msg","删除成功!"<span style="color: rgba(0, 0, 0, 1)">); }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{ request.setAttribute(</span>"msg","删除失败!"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">转发到index.jsp页面</span> request.getRequestDispatcher("index.jsp"<span style="color: rgba(0, 0, 0, 1)">).forward(request,response); }</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span>(act.equals("edit"<span style="color: rgba(0, 0, 0, 1)">)){ }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{ response.sendRedirect(</span>"index.jsp"<span style="color: rgba(0, 0, 0, 1)">); } } </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span> doGet(HttpServletRequest request, HttpServletResponse response) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException, IOException { doPost(request,response); }
}
index.jsp
<%@ page import="com.tax.dao.BookDao" %> <%@ page import="com.tax.dao.BookDaoImpl" %> <%@ page import="com.tax.model.Book" %> <%@ page import="java.util.ArrayList" %> <%@ page import="java.util.List" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <% BookDao dao = new BookDaoImpl(); List<Book> books = dao.getAllBooks(); %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>图书列表</title> <style> body{ font-size:14px; } #tabBooks { width: 80%; }#tabBooks, #tabBooks td </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> border-collapse</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)"> collapse</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">}</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(128, 0, 0, 1)"> .red</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> color</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">red</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">}</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(128, 0, 0, 1)"> .green</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">{</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(255, 0, 0, 1)"> color</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">:</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">green</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">;</span> <span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">}</span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">style</span><span style="color: rgba(0, 0, 255, 1)">></span>
</head>
<body>
<h2>图书列表</h2>
<table border="1" id="tabBooks">
<tr>
<td>
<input type="checkbox" id="chbAll"/>
</td>
<td>序号</td>
<td>书名</td>
<td>价格</td>
<td>类型</td>
<td>状态</td>
<td>操作</td>
</tr>
<%for (int i = 0; i < books.size(); i++) {%>
<tr>
<td>
<input type="checkbox" name="id" value=""/>
</td>
<td>
<%=i + 1%>
</td>
<td><%=books.get(i).getTitle()%>
</td>
<td><%=books.get(i).getPrice()%>
</td>
<td><%=books.get(i).getTypename()%>
</td>
<td class="<%=books.get(i).getState().equals("未借出 ")?"green":"red"%>">
<%=books.get(i).getState()%>
</td>
<td>
<a href="BookServlet?act=delete&id=<%=books.get(i).getId()%>" class="delete" onclick="return isDel()">删除</a>
</td>
</tr>
<%}%>
</table>
<script>
// var items=document.querySelectorAll(".delete");
// for(var i=0;i<items.length;i++){
// items[i].onclick=function () {
// return confirm("您确定要删除吗?");
// }
// }<span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">function</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> isDel() { </span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 255, 1)">return</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)"> confirm(</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">您确定要删除吗?</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">'</span><span style="background-color: rgba(245, 245, 245, 1); color: rgba(0, 0, 0, 1)">); }
</script>
</body>
</html>
结果:
2.7、参考代码
https://git.coding.net/zhangguo5/WebReadMyBatis.git
三、MyBatis 总结
使用 jdbc 开发时,和 mybatis 相比的不足
1,数据库连接,使用时就创建,不使用就释放,对数据库进行频繁连接开关和关闭,造成数据库资源浪费,影响数据库的性能
解决:使用数据库连接池管理数据库的连接
2,sql 语句使用硬编码在 java 程序中,修改 sql 语句,就需要重新编译 java 代码,不利于系统维护
解决:把 sql 语句放在 xml 配置文件中,修改 sql 语句也不需要重新编译 java 代码
3,向预编译语句 PreparedStatement 中设置参数,对占位符位置和设置参数值,硬编码,修改 sql 语句也不需要重新编译 java 代码
解决:把 sql 语句和占位符设置参数值放在 xml 配置文件中
4,从 result 中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码
解决:将查询的结果集,自动映射成 java 对象
二 mybatis 框架,是一个持久层框架,是 apache 下的顶级项目
mybatis 让程序员将主要精力放在 sql 上,通过 mytabis 提供的映射方式,自动生成满足需要的 sql 语句
mybatis 可以向 PreparedStatement 中输入参数自动进行输入映射,将查询结果集灵活的映射成 Java 对象(输出映射),输入映射和输出映射这是 mybatis 的核心
mybatis 框架执行流程图
三 mybatis 的工作环境搭建和架构示意图
四 mybatis 的开发
1. 映射文件的开发如下图
2, 映射文件配置好了之后,还需要在全局配置文件 sqlMapConfig.xml 中添加映射文件
3,sqlsession 会话去执行操作查询数据库映射文件,下图中的错误纠正为’%${value}%’
查询出的是单条记录使用 selectOne,下图中的错误纠正为把“1”改为 int 类型的 1
sqlsession.selectOne(“test.findUserById”, 1);
查询出的是多条记录使用 selectList
sqlsession.selectList(“test.findUserByName”, “hello”);
4,添加用户映射文件配置如下:
程序代码:
5,总结:
四 mybatis 开发 dao 方法
mybatis 的配置文件不变
1,先使用原型的开发 dao 方法
开发接口
2, 开发接口实现
3, 测试代码
4,总结
五 mybatis 利用 mapper 代理开发 dao(重点掌握)
mapper 代理开发,就不需要接口的实现类,只需要接口 UserMapper.java 和映射文件 UserMapper.xml 就可以了,但是遵循一定的开发规范:
1,在 UserMapper.xml 文件中 namespace 等于 UserMapper 接口地址
2,UserMapper.java 接口中的方法名要和 UserMapper.xml 中的 statement 的 id 一致
3,UserMapper.java 接口中的方法输入参数要和 UserMapper.xml 中的 statement 的 parameterType 指定的类型一致
4,UserMapper.java 接口中的方法的返回值类型要和 UserMapper.xml 中的 statement 的 resultType 指定的类型一致
测试代码:
上图画线区域: 这里没有实现接口的实现类,而是使用 mybatis 生成的代理对象来生成 UserMappper 接口的对象,从而能够调用其方法
mapper 代理开发 dao 出现的问题总结:
1,代理对象内部调用 selectOne 或 selectList
如果 mapper 方法返回单个 pojo 对象(非集合对象),代理对象内部通过 selectOne 查询数据库,也可以使用 selectList 查询。
如果 mapper 方法返回集合对象,代理对象内部通过 selectList 查询 数据库,不能使用 selectOne 查询,否则会出错。
问题是: 编译期间不会报错,二者容易写错使用。
2,mapper 接口方法参数只有一个
根据规范编写的代理对象的传入参数只能有一个(mapper.xml 文件中的 parameterType 参数只有一个),不利于系统的扩展
解决:即使 mapper 接口中只有一个参数,可以使用包装类型的 pojo 满足不同的业务方法需求
mybatis 的一些细节剖析:
1,全局配置文件 sqlMapConfig.xml 中配置内容如下:
-
properties(属性)
注意:mybatis 将按照下面的顺序来加载属性:
(1)在 properties 元素体内定义的属性首先被读取。(可以在此属性中加入 jdbc 的配置文件 db.properties), 在 sqlMapConfig.xml 中就不需要对数据库连接参数进行硬编码了。 -
settings 全局参数设置
mybatis 框架运行时可以调整一些运行参数,会影响 mybatis 运行行为,所以建议不要随便修改
比如:二级缓存,开启延时加载。。。 - typeAliases(别名) 重点掌握
<typeAliases>
<!-- 针对单个别名定义
type:类型的路径
alias:别名 -->
<typeAlias type="com.jary.mybatis.po.User" alias="user" />
<!-- 还可以进行批量别名定义
指定包名,mybatis 自动扫描包中的 po 类 -->
<package name="com.jary.mybatis.po" />
</typeAliases>
上面的别名定义后,在 mapper.xml 中就可以这样使用了
user 代替了输出结果类型 com.jary.mybatis.po.User。
4. 映射文件(mapper)
通过 resource 加载单个的映射文件
<mapper resource="mapper/UserMapper.xml" />
- 1
通过 mapper 接口加载单个 mapper, 要遵循一定的规范:
(1)前提是使用 mapper 代理开发(已经有 4 个规范)
(2)需要将 mapper 接口类名和 mapper.xml 映射文件名称保持一致,且在同一目录下
<mapper class="com.jary.mybatis.mapper.UserMapper" />
- 1
通过批量加载 mapper(推荐使用):实现条件是
要满足 mapper 接口加载映射文件和使用 mapper 代理开发同时满足
mybatis 的一些细节剖析结束
mybatis 的核心输入映射和输出映射开始:
输入映射
通过 parameterType 指定输入参数类型,类型可以是简单类型、hashmap、pojo 的包装类型
1,传递 pojo 的包装对象
(1)需求
完成用户信息的综合查询,需要传入查询条件复杂(可能包括用户信息,商品信息,商品订单等),这样靠一个 parameterType 只能传入一个输入参数,所有需要 pojo 的包装类型来实现
(2)定义包装类型 pojo
针对上面的需求,在包装类型的 pojo 中把这些复杂的查询条件包装进去,定义包装类 UserQueryVo,把需要查询的条件全部定义在里面
上图中标注的用户查询条件使用的是 User 的扩展类(因为 User 类一般是由逆向工程自动生成的,不要进行修改,所有使用的扩展类来实现)
映射文件 UserMapper.xml 配置
UserMapper.java 接口文件的配置
上图中,把包装类作为参数传入,返回值是一个用户列表所以用 list 集合接收
测试代码如下图:
输出映射
1,resultType
使用 resultType 进行输出映射时,只有查询输出结果列名和 pojo 中的属性名一致才可以,映射成功
如果查询出来的列名和 pojo 中的属性名没有一个一致的,就不会创建 pojo 对象
如果查询出来的列名和 pojo 中的属性名有一个一致,就会创建 pojo 对象
输出 pojo 对象和 pojo 列表
不管是输出的 pojo 单个对象还是一个列表(list 中包含 pojo),在 mapper.xml 中 resultType 指定的类型是一样的
在 mapper.java 指定的方法返回值类型不一样:
(1)输出单个 pojo 对象,方法返回值是个单个对象类型
(2)输出 pojo 对象 list,方法返回值就是 list 对象类型
在动态代理对象中,是根据 mapper 方法的返回值类型来确定是调用 selectOne(返回单个对象 ) 还是 selectList(返回集合对象)
2,resultMap
使用 resultMap 进行映射时,查询结果列名和 pojo 的属性名不一致时,resultMap 会对列名和 pojo 属性名进行映射,保证其成功映射
使用 resultMap 需要这二步:
(1)定义 resultMap
(2)使用 resultMap 作为 statement 的输出映射类型
mybatis 的核心输入映射和输出映射结束:
mybatis 的动态 sql 和 sql 片段开始:
动态 sql
mybatis 核心就是对 sql 语句进行灵活操作,通过表达式进行判断,对 sql 进行灵活拼接和组装。
需求:用户信息查询的综合信息需要使用动态 sql
对查询条件进行判断,如果出入参数不为空,才进行拼接
测试代码需要注意的是如下图:
如果不设置某个值,条件将不拼接在 sql 中
sql 片段
需求:将上面的动态 sql(重复的 sql 语句)抽取出来做成一个片段,方便其他 statement 语句重复使用 sql 片段
使用 sql 片段
使用 foreach 标签遍历
给 sql 传入数组或者集合时,mybatis 使用 foreach 解析
需求:在用户信息的综合查询中增加多个 id 传入
sql 语句如下:
select * from user where id=1 or id=3 or id=5
也可以使用 select * from user where id in(1,3,5)
mybatis 的动态 sql 和 sql 片段结束
mybatis 高级映射开始:
一、 高级映射一对一查询(使用到 assocition 标签实现关联对象的一对一查询映射),分别使用 resultType 和 resultMap,并且比较二者的区别
还有一点就是,resultType 查询关联列表结果列如果和 pojo 属性名不一致,需要自己创建扩展类(继承包括结果集列名多的 pojo 对象,这样可以少写一点属性名)。resultMap 则不需要创建扩展类,而是把关联信息的对象注入,从而实现结果集列名和 pojo 属性名保持一致。
二、高级映射一对多查询(使用 collection 标签来实现关联对象的一对多查询映射),一对多,就是关联的对象查询结果是一个 List 集合
开发步骤:
(1)首先写 sql 语句
需求:查询订单及订单明细信息(一个订单包含多个订单明细,所以一对多)
主表:订单表
关联表:订单明细表
经过之前一对一查询(用户的订单)的分析,我们只需要在此基础上关联订单明细表即可。
(2)pojo 类 (resultType 时用到扩展类,这里我们使用 resultMap 不需要包装类)
(3)mapper.xml(这里我们使用了 resultMap 的继承,不需要重新关联订单表和用户表,通过继承之前的一对一(用户查询订单)所写的二个表,可以减少大量的重复代码。同时使用了 collection 集合标签将关联查询出的多条记录映射到 List 集合中)
(4)mapper.java
一对多查询总结:
mybatis 使用 resultMap 的 collection(resultType 没有此标签)对关联查询的多条记录映射到一个 list 集合中。
使用 resultType 通过双重循环遍历可以实现,去除重复记录,将订单明细映射在 orderdetail 中(了解)
多对多查询实例和上边类似。主要是搞清楚各个表之间的对应关系,订单的 collection 中嵌套订单明细的 collection,而订单明细的 collection 中嵌套商品信息。
mybatis 高级映射结束
mybatis 的延迟加载和缓存技术开始
mybatis 一级缓存
mybatis 的二级缓存
mybatis 默认是没有开启二级缓存的。
开启二级缓存需要在 mybatis 的全局配置文件 sqlMapConfig.xml 中加入
除了开启二级缓存开关外,还需要在各自的 mapper.xml 中开启二级缓存。
原理图:
如上图:sqlsession1 去查询 id 为 1 的用户信息,查询到用户信息就会查询数据存放在二级缓存区域(hashmap)中
sqlsession2 去查询 id 为 1 的用户信息,首先去缓存中查找是否存在数据,如果存在就直接从二级缓存中取出数据。
二级缓存和一级缓存的区别:二级缓存的范围更大,多个 sqlsession
可以共享 usermapper 的二级缓存。
二级缓存是根据 mapper 的 namespace 来划分的,相同 namaspace 下的 mapper 共享二级缓存,反之
如果 sqlsession3 去执行相同 mapper 下 sql,并执行 commit()操作,则清空该命名空间下的二级缓存
二级缓存的测试代码:
上面涂黄部分要特别注意,sqlsession 关闭时才可以把数据写到二级缓存区域中,如果本 namespace 下的 sqlsession 执行了 commit()操作,二级缓存就会清空
禁用二级缓存
也可以禁用单个查询的二级缓存,这样要保证每次查询的都是最新数据。
刷新二级缓存(就是清空缓存,切记)
总结:一般情况下,执行 commit() 操作之后,都要刷新缓存,因此 flushCache 都设为 true,来避免数据的脏读。
mybatis cache 的参数设置
flushInterval(刷新间隔),可以为任意整数,单位为毫秒值,这个比较有用。
mybatis 和第三方分布式缓存框架整合(ehcache,redis,memcache)
mybatis 在缓存方面还是比较弱,特别是分布式缓存不支持
我们的系统为了提高系统并发,性能,一般对系统进行分布式部署(集群部署方式)
整合方法
mybatis 提供了一个 cache 接口,如果要实现自己的缓存逻辑,实现 cache 接口即可
mybatis 和 ehcache 整合,mybatis 和 ehcache 整合包中提供了一个 cache 接口的实现类。
二级缓存的应用场景(实际开发中用 刷新间隔)
二级缓存额局限性
细粒度缓存, 就是修改一个商品信息(即执行 commit()方法),只修改缓存中这一个商品的信息,其余的信息不清空。
mybatis 的延迟加载和缓存技术结束
mybatis 和 spring 的整合(重点掌握)开始
1、整合的思路:
(1)首先需要 spring 通过单例方式管理 sqlSessionFactory
(2)spring 和 mybatis 整合生成代理对象,使用 SqlSessionFactory 创建 sqlSession 会话(此步是由 spring 和 mybatis 整合自动完成)
(3)持久层的 mapper,dao 都需要由 spring 来管理
2、环境的搭建
上面的 sqlmap 目录下的 User.xml 是为了原始 dao 开发使用的。还要加载 spring,mybatis,mybatis-srping 等 jar 包。
3、在 spring 的配置文件中配置 sqlSessionFactory 和数据源
sqlSessionFactory 在 mybatis 和 spring 的整合包下
上图中:使用 C3P0 配置数据库连接池,属性参数名要按照规定写,不能自己定义,否则会报错,而使用 dbcp 就可以自定义参数名,这点注意。
在加载配置文件时,都要加上类路径名 classpath
在使用原始 dao 开发时,属性 name 值要与 UserDaoImpl 类中变量名一致(特别是大小写)
4、* 原始 Dao 的开发(和 spring 整合后)*
4.1 User.xml(也称 mapper.xml 更准确)
和 spring 整合后,需要使用 spring 来管理 mapper,spring 配置文件为 applicationContext.xml
还有 mybatis 的配置文件来加载 User.xml
4.2 UserDAO
基本上不用改变
4.3 UserDaoImpl(重点在 Dao 的实现类上)
上图中的代码最重要的就是继承了 SqlSessionDaoSupport 通过 this.getSqlSession() 来得到 SqlSession 会话
这里也不需要写 sqlSession 的事务提交(更新操作不用写)和 sqlSession 关闭
4.4 测试代码
5、使用 mapper 代理来开发 (mybatis 和 spring 整合后)
和利用原始 dao 开发差不多,只是不需要 dao 接口的实现类
而是根据一个规范来实现 dao 接口生成代理对象
5.1 规范:
(1)mapper.xml 中的 namespace 命名空间等于 mapper.java 的全路径名
(2)mapper.xml 和 mapper.java 应在同一个目录下
(3)mapper.xml 中的 statement 语句的输入参数 paramType 类型应与 mapper.java 中方法中传递的参数类型一致
(4)mapper.xml 中的 statement 语句的输出参数 resultType 类型应与 mapper.java 中方法返回值类型一致
5.2 让 spring 来管理 mapper,在配置文件中
重点在这里,使用 mybatis 和 spring 的整合包中 MapperFactoryBean 来实现 mapper 接口生成代理对象
属性值有 mapperInterface 和 sqlSessionFactory
总结:此方法存在一个大问题,需要针对每个 mapper 进行配置,太麻烦
终极解决方案: 通过 mapper 批量扫描,从 mapper 包中扫描出 mapper 接口,自动创建代理对象并且在 spring 容器中注册
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
- 1
上面代码,不能使用 ref 而是使用 value, 刚开始用错了。
开发中推荐使用自动扫描,
mybatis 和 spring 的整合(重点掌握)结束
mybatis 的逆向工程(了解会用就行)
generator.xml 的配置,这里要记住,上图中最下边 table 后面的一长串值等于 false 的属性,是为了不生成其他与我们无关的 example 等代码
下面需要 mybatis-generator-core-1.3.2.jar 和 generator.xml 文件在同于目录下,并且建立 src 目录接收生成的文件
生成后的如下图
没有了 example 的无用类了,比较干净,推荐使用
1. 接口绑定:两种方法,基于注解或者基于 xml 文档 mapper,但要注意 mapper 的 namespace 要与接口路径完全一致。
2.orm 格式转换:通过设置 resultMap 和 ResultType,将数据库中的记录转换为代码的 bean 对象。得到 list 或者对象。
3. 通过 parameterType 接收参数,进行动态 sql 生成。运用 ognl 表达式
4. 走缓存,设置二级缓存。设置二级缓存源。
5. 为什么要通过 orm 框架来走缓存呢?因为自己配置缓存策略相对复杂,比如当 insert/update/delete 时,要清除相应的缓存。当某些情况 select 又要添加进缓存。
6.orm 框架,orm 框架,它是怎么进行对象和数据库中表的转换的呢?答:数据库中的表要与代码中的类一一对应,包括属性。这样不就能进行匹配转换了嘛。
5. 返回 list,必须要配置 resultMAp
6.insert 操作时,要注意主键 主键生成策略,要设置 useGeneraterKey = true, 和 keyProperty="id",指定哪个是主键
<insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id"> insert into user(userName,userAge,userAddress) values(#{userName},#{userAge},#{userAddress}) </insert>
7.spring 在于 mybatis 集成时,spring 负责什么呢?谁来维护 datasource,谁来建立 sqlSessionFactory?
答:spring 作为多个框架的粘合剂,spring 负责建立 datasource,sqlsessionFactpry。充分利用 spring 的 ioc 和 aop 功能。
spring 配置文件:applicationContext.xml
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">//spring 管理配置 datasource <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> //spring 管理配置 sqlsessionFactory
<!--dataSource 属性指定要用到的连接池 -->
<property name="dataSource" ref="dataSource"/>
<!--configLocation 属性指定 mybatis 的核心配置文件 -->
<property name="configLocation" value="config/Configuration.xml"/>
</bean>
8.Mybatis 的 dao 实现接口(接口绑定),是由 mybatis 来实现的,那又怎么来使用这个实现类呢?
答:当然是注册到 spring 里了,作为一个 bean 使用。
即:mybatis 的 dao 实现类,也都要注册到 spring 的 ioc 容器中,以便利用 spring 的 ioc 和 aop 功能。
注意此时 dao 实现类,的具体类是 mybatis 固定的 org.mybatis.spring.mapper.MapperFactoryBean 类,这个类专门用来生成具体的 dao 实现类。
但要记住,一切的增删改查都是通过 session 来进行的,所以 dao 实现类要 di 依赖注入 sqlSessionFactory 这个属性。
再利用 mapperInterface 指定具体的 mapper 接口类。
spring 配置文件:applicationContext.xml
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <!--sqlSessionFactory 属性指定要用到的 SqlSessionFactory 实例 --> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> <!--mapperInterface 属性指定映射器接口,用于实现此接口并生成映射器对象 --> <property name="mapperInterface" value="com.yihaomen.mybatis.inter.IUserOperation" /> </bean>
9. 即:mybatis 的 dao 实现类,也都要注册到 spring 的 ioc 容器中,以便利用 spring 的 ioc 和 aop 功能。
10.spring 的配置文件 applicationContext.XML 负责配置与数据库相关,与 mybatis sqlSessionFaction 整合,扫描所有 mybatis mapper 文件等相关内容。
事务管理器也在 spring 的配置文件中配置,同时要依赖注入 datasource 属性
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
11.mybatis 的分页功能,可以自己利用 mysql 代码实现,也可以利用 mybatis 分页插件, 如 pageHelper
12.mybatis 的传入参数只能是一个,只能有 1 个。可以是各种Java的基本数据类型:包含 int,String,Date 等。基本数据类型作为传参,只能传入一个。通过 #{参数名} 即可获取传入的值 ,复杂数据类型:包含 JAVA 实体类、Map。通过 #{属性名} 或 #{map 的 KeyName} 即可获取传入的值,但是如果想传入一个 collection 怎么办呢?
经查找后发现可以使用 mapper 配置文件中的 foreach 语句,借用别人写的文章:
13. foreach
对于动态 SQL 非常必须的,主是要迭代一个集合,通常是用于 IN 条件。List 实例将使用“list”做为键,数组实例以“array” 做为键。
foreach 元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。
14. 在Java实体对象对中,一对多可以根据 List 和 Set 来实现,两者在 mybitis 中都是通过 collection 标签来配合使用
15.
一对一关联
根据班级 id 查询班级信息 (带老师的信息) 10 ##1. 联表查询 11 SELECT * FROM class c,teacher t WHERE c.teacher_id=t.t_id AND c.c_id=1;
<select id="getClass" parameterType="int" resultMap="ClassResultMap"> 24 select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=#{id} 25 </select> 26 <!-- 使用 resultMap 映射实体类和字段之间的一一对应关系 --> 27 <resultMap type="me.gacl.domain.Classes" id="ClassResultMap"> 28 <id property="id" column="c_id"/> 29 <result property="name" column="c_name"/> 30 <association property="teacher" javaType="me.gacl.domain.Teacher"> 31 <id property="id" column="t_id"/> 32 <result property="name" column="t_name"/> 33 </association> 34 </resultMap>
<!-- 37 方式二:嵌套查询:通过执行另外一个 SQL 映射语句来返回预期的复杂类型 38 SELECT * FROM class WHERE c_id=1; 39 SELECT * FROM teacher WHERE t_id=1 //1 是上一个查询得到的 teacher_id 的值 40 --> 41 <select id="getClass2" parameterType="int" resultMap="ClassResultMap2"> 42 select * from class where c_id=#{id} 43 </select> 44 <!-- 使用 resultMap 映射实体类和字段之间的一一对应关系 --> 45 <resultMap type="me.gacl.domain.Classes" id="ClassResultMap2"> 46 <id property="id" column="c_id"/> 47 <result property="name" column="c_name"/> 48 <association property="teacher" column="teacher_id" select="getTeacher"/> 49 </resultMap> 50 51 <select id="getTeacher" parameterType="int" resultType="me.gacl.domain.Teacher"> 52 SELECT t_id id, t_name name FROM teacher WHERE t_id=#{id} 53 </select>
MyBatis 中使用 association 标签来解决一对一的关联查询,association 标签可用的属性如下:
- property: 对象属性的名称
- javaType: 对象属性的类型
- column: 所对应的外键字段名称
- select: 使用另一个查询封装的结果
一对一关联
根据班级 id 查询班级信息 (带老师的信息) 10 ##1. 联表查询 11 SELECT * FROM class c,teacher t WHERE c.teacher_id=t.t_id AND c.c_id=1;
<select id="getClass" parameterType="int" resultMap="ClassResultMap"> 24 select * from class c, teacher t where c.teacher_id=t.t_id and c.c_id=#{id} 25 </select> 26 <!-- 使用 resultMap 映射实体类和字段之间的一一对应关系 --> 27 <resultMap type="me.gacl.domain.Classes" id="ClassResultMap"> 28 <id property="id" column="c_id"/> 29 <result property="name" column="c_name"/> 30 <association property="teacher" javaType="me.gacl.domain.Teacher"> 31 <id property="id" column="t_id"/> 32 <result property="name" column="t_name"/> 33 </association> 34 </resultMap>
<!-- 37 方式二:嵌套查询:通过执行另外一个 SQL 映射语句来返回预期的复杂类型 38 SELECT * FROM class WHERE c_id=1; 39 SELECT * FROM teacher WHERE t_id=1 //1 是上一个查询得到的 teacher_id 的值 40 --> 41 <select id="getClass2" parameterType="int" resultMap="ClassResultMap2"> 42 select * from class where c_id=#{id} 43 </select> 44 <!-- 使用 resultMap 映射实体类和字段之间的一一对应关系 --> 45 <resultMap type="me.gacl.domain.Classes" id="ClassResultMap2"> 46 <id property="id" column="c_id"/> 47 <result property="name" column="c_name"/> 48 <association property="teacher" column="teacher_id" select="getTeacher"/> 49 </resultMap> 50 51 <select id="getTeacher" parameterType="int" resultType="me.gacl.domain.Teacher"> 52 SELECT t_id id, t_name name FROM teacher WHERE t_id=#{id} 53 </select>
MyBatis 中使用 association 标签来解决一对一的关联查询,association 标签可用的属性如下:
- property: 对象属性的名称
- javaType: 对象属性的类型
- column: 所对应的外键字段名称
- select: 使用另一个查询封装的结果
15.
2.6、MyBatis 一对多关联查询总结
MyBatis 中使用 collection 标签来解决一对多的关联查询,ofType 属性指定集合中元素的对象类型。
本文部分转自 http://www.cnblogs.com/xdp-gacl/p/4264440.html
16.mybatis 调用存储过程
三、编辑 userMapper.xml编辑 userMapper.xml 文件,添加如下的配置项
复制代码
1 <!--
2 查询得到男性或女性的数量, 如果传入的是 0 就女性否则是男性
3 -->
4 <select id="getUserCount" parameterMap="getUserCountMap" statementType="CALLABLE">
5 CALL mybatis.ges_user_count(?,?)
6 </select>
7
8 <!--
9 parameterMap.put("sexid", 0);
10 parameterMap.put("usercount", -1);
11 -->
12 <parameterMap type="java.util.Map" id="getUserCountMap">
13 <parameter property="sexid" mode="IN" jdbcType="INTEGER"/>
14 <parameter property="usercount" mode="OUT" jdbcType="INTEGER"/>
15 </parameterMap>
复制代码
四、编写单元测试代码复制代码
1 package me.gacl.test;
2
3 import java.util.HashMap;
4 import java.util.List;
5 import java.util.Map;
6
7 import me.gacl.custom.model.ConditionUser;
8 import me.gacl.domain.User;
9 import me.gacl.util.MyBatisUtil;
10 import org.apache.ibatis.session.SqlSession;
11 import org.junit.Test;
12
13 /**
14 * @author gacl
15 * 测试调用存储过程
16 /
17 public class Test6 {
18
19 @Test
20 public void testGetUserCount(){
21 SqlSession sqlSession = MyBatisUtil.getSqlSession();
22 /*
23 * 映射 sql 的标识字符串,
24 * me.gacl.mapping.userMapper 是 userMapper.xml 文件中 mapper 标签的 namespace 属性的值,
25 * getUserCount 是 select 标签的 id 属性值,通过 select 标签的 id 属性值就可以找到要执行的 SQL
26 */
27 String statement = "me.gacl.mapping.userMapper.getUserCount";// 映射 sql 的标识字符串
28 Map<String, Integer> parameterMap = new HashMap<String, Integer>();
29 parameterMap.put("sexid", 1);
30 parameterMap.put("usercount", -1);
31 sqlSession.selectOne(statement, parameterMap);
32 Integer result = parameterMap.get("usercount");
33 System.out.println(result);
34 sqlSession.close();
35 }
36 }
复制代码