Mybatis 复习

1 什么是MyBatis

MyBatis是一个优秀的持久层框架,它对JDBC操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、 结果集检索等JDBC繁杂的过程代码 。

MyBatis通过 xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过 Java 对象和 statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由MyBatis框架执行sql并将结果 映射成Java对象并返回。

1.2 MyBatis的优点

  1. 简单易、 没有任何第三方依赖,最简单安装只要两个jar文件 + 配置几个sql映射文件,
  2. Mybatis不会对应用程序或者数据库的现有设计强加任何影响,sql写在xml里,便于统一管理和优 化。 通过sql语句可以满足操作数据库的所有需求。
  3. 解除sql与程序代码的耦合: 通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测 试。 sql和代码的分离,提高了可维护性 。
  4. 提供丰富且强大的标签 。

1.3 为什么要学Mybatis

当使用java代码操作数据库时,需要用到 JDBC编程 ,但JDBC在使用时存在问题:

1. 数据库连接使用时就创建,不使用时便立即释放,从而对数据库进行频繁的操作,导致资源的浪  

费、影响性能。
2. sql都是硬编码到Java程序中,如果改变sql,那么得重新编译Java代码,不利于系统后期的维护。
3. 向PreparedStatement设置参数,也是硬编码到Java程序中,不利于后期的维护。
4. 从resultset遍历结果集数据时,也存在硬编码,不利于后期系统的维护。

1.4 MyBatis整体架构

  1. MyBatis配置: mybatis-config.xml(名称不固定),此文件作为MyBatis的全局(核心)配置文件,配置了 MyBatis的运行环境等信息。 mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。
  2. 通过MyBatis环境等配置信息构造SqlSessionFactory,即会话工厂。
  3. 由会话工厂创建SqlSession即会话,操作数据库需要通过SqlSession进行。
  4. MyBatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行 器、一个是缓存执行器。
  5. MappedStatement也是MyBatis一个底层封装对象,Mybatis将SQL的配置信息加载成为一个个 MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存 中。mapper.xml文件中一个sql对应一个MappedStatement对象,sql的id即是MappedStatement的 id。
  6. MappedStatement对sql执行输入参数进行定义,包括HashMap、基本类型、字符串类型、实体类 类型,Executor通过MappedStatement在执行sql前将输入的Java对象映射至sql中,输入参数映射就是 JDBC编程中对PreparedStatement设置参数。
  7. MappedStatement对sql执行输出结果进行定义,包括HashMap、基本类型、字符串类型、实体类 类型,Executor通过MappedStatement在执行sql后将输出结果映射至Java对象中,输出结果映射过程 相当于JDBC编程中对结果的解析处理过程。

1.5 vo、po、dto、bo、pojo、entity 等层的解释。

  • VO:值对象 ,由new创建,由GC回收,存放指定的数据,可以和表数据不一致。
  • PO:是 ORM 框架中Entity,PO属性和数据库中表的字段形成一一对应关系 加上get和set方法 ;
  • entity :和PO的功能类似,和数据表一 一对应,一个实体一张表 。
  • dto: 数据传输对象 ,存放页面需要的表的部分字段。
  • bo: BO是封装业务逻辑的Java对象,封装了多个po,vo,通过调用DAO方法,进行业务操作。
  • pojo:简单来说可以理解成不包含业务逻辑的单纯用来存储数据的Java类 , 可以转化为PO、DTO、VO。
    • 一个POJO持久化以后就是PO; 直接用它传递、传递过程中就是DTO; 直接用来对应表示层就是VO;

2 建立MyBatis项目

2.1新建一个java项目,导入maven包

<dependencies><!-- mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version></dependency><!-- oracle:大家在引入oracle依赖的时候肯定出错 --><dependency><groupId>com.oracle</groupId><artifactId>ojdbc6</artifactId><version>11.2.0.1.0</version></dependency><!--  mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version></dependency><!-- log4j Mybatis的日志输出组件 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>
</dependencies>

2.2 编写MyBatis中全局配置文件 mybatis-config.xml

 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><!-- configuration 文件的根节点 -->
<!-- MyBatis配置文件报错:
在编写xml配置文件引入DTD约束时,可能会出现这个错误提示 URI is not registered(Settings | 
Languages & Frameworks | Schemas and DTDs),此时使用快捷键,选择Fetch external 
resource 或 Ignore external resource选项。或者直接在设置settings -> languages&frameworks -> schemas and dtds 中添加出问题的路径。 -->
<configuration><!--properties 用于引入外部的properties配置文件resource:引入类路径下的文件url:引入磁盘或网路--><properties/><!-- environments:多个配置环境;通过default属性可以对多个环境快速切换。environments default属性的值必须和某个environment的id值一致。--><!-- 和spring整合后 environments配置将废除,了解即可 --><environments default="mysql"><environment id="mysql"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&amp;useSSL=false"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments></configuration>

2.3 导入一个数据库SQL

CREATE TABLE `dept`  (`deptno` int PRIMARY KEY AUTO_INCREMENT,`dname` varchar(20),`loc` varchar(40)
);INSERT INTO `dept` VALUES (10, 'ACCOUNTING', 'NEW YORK');INSERT INTO `dept` VALUES (20, 'RESEARCH', 'DALLAS');INSERT INTO `dept` VALUES (30, 'SALES', 'CHICAGO');INSERT INTO `dept` VALUES (40, 'OPERATIONS', 'BOSTON');CREATE TABLE `emp`  (`empno` int PRIMARY KEY AUTO_INCREMENT,`ename` varchar(20),`job` varchar(20),`mgr` int,`hiredate` date,`sal` double,`comm` double,`deptno` int,CONSTRAINT `FK_EMP_DEPTNO` FOREIGN KEY (`deptno`) REFERENCES `dept` (`deptno`));INSERT INTO `emp` VALUES (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 1300, NULL, 20);INSERT INTO `emp` VALUES (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 2100, 300, 30);INSERT INTO `emp` VALUES (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1750, 500, 30);INSERT INTO `emp` VALUES (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 3475, NULL, 20);INSERT INTO `emp` VALUES (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1750, 1400, 30);INSERT INTO `emp` VALUES (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 3350, NULL, 30);INSERT INTO `emp` VALUES (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2950, NULL, 10);INSERT INTO `emp` VALUES (7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19', 3500, NULL, 20);INSERT INTO `emp` VALUES (7839, 'KING', 'PRESIDENT', NULL, '1981-11-17', 5500, NULL, 10);INSERT INTO `emp` VALUES (7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 2000, 0, 30);INSERT INTO `emp` VALUES (7876, 'ADAMS', 'CLERK', 7788, '1987-05-23', 1600, NULL, 20);INSERT INTO `emp` VALUES (7900, 'JAMES', 'CLERK', 7698, '0198-12-31', 1450, NULL, 30);INSERT INTO `emp` VALUES (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3500, NULL, 20);INSERT INTO `emp` VALUES (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1800, NULL, 10);

2.4 编写实体类

import java.util.Date;public class Emp {private Integer empno;private String ename;private String job;private Integer mgr;private Date hiredate;private Double sal;private Double comm;private Integer deptno;// 省略set,get方法}

2.5 编写映射文件

在src/main/resources下创建mapper目录,在该目录下创建sql映射文件Emp.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">
<!--
namespace: 命名空间,作用是mapper文件进行分类管理,用于隔离sql语句。
注意:如果使用mapper代理的方式进行开发,namespace有特殊的作用。-->
<mapper namespace="emp"><!-- 通过员工编号查询员工信息 --><!--通过<select>标签编写查询语句id: 映射文件中SQL语句的唯一标识。mybatis会将SQL语句封装到MappedStatement对象中,所以此处的id也可以标识MappedStatement对象的id;注意:同一个mapper文件中id不能重复,而且id在mapper代理模式下有着重要作用;parameterType: 输入参数的类型。sql语句的占位符:#{};#{empno}:其中empno表示接收输入的参数值,参数名称为empno;但是如果参数的类型为简单类型(基本数据类型、包装类、字符串类型),参数名称可以任意指定;resultType: 输出参数的类型。需要指定输出数据为Java中的数据类型(实体类的全限定名);--><select id="selectById" parameterType="java.lang.Integer" resultType="com.gs.entity.Emp">select empno, ename, job, hiredate, mgr, sal, comm, deptno from emp where empno=#{empno}</select>
</mapper>

将这个mapper文件都丢到全局配置文件中。

<!-- 加载映射文件的位置 --><mappers><mapper resource="mapper/Emp.xml"/></mappers>

2.6 log4j配置 (在控制台可查看sql语句)

Mybatis日志输出:log4j.properties配置文件。

#井号表示注释,配置内容为键值对格式,每行只能有一个键值对,键值对之间以=连接
#指定logger#设定log4j的日志级别和输出的目的地
#INFO日志级别,Console和logfile输出的目的地
#等级 OFF,ERROR,WARN,INFO,DEBUG,TRACE,ALLlog4j.rootLogger=DEBUG,Console#指定appender#设定Logger的Console,其中Console为自定义名称,类型为控制台输出
log4j.appender.Console=org.apache.log4j.ConsoleAppender#设定Logger的logfile,其中logfile为自定义名称,类型为文件
#org.apache.log4j.FileAppender文件
#org.apache.log4j.RollingFileAppender文件大小到达指定尺寸后产生一个新的文件
#org.apache.log4j.DailyRollingFileAppender每天产生一个日志文件
log4j.appender.logfile=org.apache.log4j.RollingFileAppender#设定文件的输出路径
log4j.appender.logfile.File=d:/log/test.log#设定文件最大尺寸  单位可以使KB,MB,GBlog4j.appender.logfile.MaxFileSize=2048KB#输出格式
#设定appender布局Layout#   
%d 输出日志的日期和时间,指定格式:%d{yyyy-MM-dd HH:mm:ss SSS}#   
#   
#   
#   
#   
%p 输出的日志级别
%c 输出所属类的全类名
%M 方法名
%m 输出代码中指定消息
%n 一个换行符
log4j.appender.Console.layout=org.apache.log4j.PatternLayoutlog4j.appender.Console.layout.ConversionPattern=%d %p %c.%M() --%m%nlog4j.appender.logfile.layout=org.apache.log4j.PatternLayoutlog4j.appender.logfile.layout.ConversionPattern=%d %p %c.%M() --%m%n

2.7 编写测试程序 (在test路径下)

运行测试类;

/*** 测试程序*/
public class MybatisTest {@Testpublic void test() throws IOException {//1.创建读取全局配置文件的流InputStream in = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();//2.通过配置文件流创建会话工厂SqlSessionFactory factory = builder.build(in);//3.通过会话工厂创建会话对象(SqlSession)SqlSession session = factory.openSession();//4.通过会话对象操作数据/*** 查询单条记录* selectOne(String statementId, Object param)* 参数1:映射文件中的statementId,命名空间名.statementId* 参数2:向sql语句中传入的数据,注意:传入的数据类型必须与映射文件中配置的
parameterType保持一致* 返回值:就是映射文件中配置的resultType的类型* 查询多条记录* selectList()*/Emp emp = session.selectOne("emp.selectById", 7369);System.out.println(emp);//5.关闭资源session.close();}
}

3 增删改查的基本操作的实现

实现以下功能: 1. 查询所有员工信息; 2. 添加员工; 3. 更新员工; 4. 删除员工; 5. 根据员工名模糊查询。

3.1 查询所有员工信息

编写mapper文件

<!--
查询到数据返回多条记录,每一条封装在一个实体类对象中,所有的实体类对象封装在List集合中
resultType:指定的并不是集合的类型,而是单条数据所对应实体类类型
resultType="java.util.List" 错误的配置方式-->
<select id="select" resultType="com.gs.entity.Emp">select empno, ename, job, mgr, hiredate, sal, comm, deptno from emp order by empno desc
</select>

在测试类编写

public class CURDTest {@Testpublic void testSelect() throws IOException {InputStream in = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);SqlSession session = factory.openSession();}
}
/*** 查询多条记录
* selectList(statement-sql语句的id, parameter-参数)* 表示将单条记录都存储输出映射对象中,每条记录的映射对象存放在List集合中
*/
List<Emp> list = session.selectList("emp.select");
for (Emp emp : list) {System.out.println(emp);
}

3.2 添加员工

编写mapper文件

<!--
添加操作使用insert标签;
增删改操作没有resultType,只有查询有resultType;
因为增删改操作返回值都是int类型,所以我们不需要指明;
注意:给占位符赋值,#{}中编写的内容为实体类型参数中的成员变量名称;#{empno}    
Mybatis会从传递过来的参数对象里面得到emono字段的值--><insert id="insert" parameterType="com.gs.entity.Emp">insert into emp(ename,job,mgr,hiredate,sal,comm,deptno)values(#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm},#{deptno})</insert>

在测试类编写

public class CURDTest {@Testpublic void testSelect() throws IOException {InputStream in = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);SqlSession session = factory.openSession();}
}Emp emp = new Emp();emp.setEname("TOM");emp.setJob("CLARK");emp.setMgr(1);emp.setHiredate(new Date());emp.setSal(6500.0);emp.setComm(1200.0);System.out.println("新增之前的主键值为:" + emp.getEmpno());int result = session.insert("emp.insert", emp);}System.out.println("影响数据库的条数为:" + result);/*** mybatis中的事务是jdbc的事务机制,mybatis里面默认是手动提交
*/session.commit();System.out.println("新增之后的主键值为:" + emp.getEmpno());session.close();

3.3 更新员工

编写mapper文件

<update id="update" parameterType="com.gs.entity.Emp">update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},sal=#{sal},comm=#{comm},deptno=#{deptno} where empno=#{empno}</update>

在测试类编写

public class CURDTest {@Testpublic void testSelect() throws IOException {InputStream in = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);SqlSession session = factory.openSession();}
}Emp emp = new Emp();emp.setEmpno(7936);emp.setEname("JERRY");emp.setJob("MANAGER");emp.setMgr(7698);emp.setHiredate(new Date(new Date().getTime() + 1000*60*60*24));
emp.setSal(7800.0);emp.setComm(800.0);}int result = session.update("emp.update", emp);System.out.println("影响数据库的条数为:" + result);session.commit();session.close();
}

3.4 删除员工

编写mapper文件

<delete id="delete" parameterType="java.lang.Integer">delete from emp where empno=#{empno}</delete>

在测试类编写

public class CURDTest {@Testpublic void testSelect() throws IOException {InputStream in = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);SqlSession session = factory.openSession();}
}int result = session.delete("emp.delete", 7935);System.out.println("影响数据库的条数为:" + result);session.commit();}session.close();
}

3.4 根据员工名模糊查询

编写mapper文件

<!--
条件查询:模糊查询
1、#{}占位符,防止sql注入
需要在Java中将传入数据的前后拼接%符号
where ename like #{ename}2、使用字符串拼接函数
where ename like concat('%',#{ename},'%')3、${}拼接符号,实现sql的拼接
where ename like '%${value}%'
注意:${}不是占位符,如果输入参数为简单类型,${}中的内容必须为value-->
<select id="selectByEname1" parameterType="java.lang.String" 
resultType="com.gs.entity.Emp">select empno,ename,job,mgr,hiredate,sal,comm,deptno from empwhere ename like #{ename}</select>

在测试类编写

public class CURDTest {@Testpublic void testSelect() throws IOException {InputStream in = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);SqlSession session = factory.openSession();}
}String ename = "S";List<Emp> list = session.selectList("emp.selectByEname1", "%"+ename+"%");for (Emp emp : list) {System.out.println(emp);}session.close();
}

4 总结

4.1 parameterType和resultType

  1. parameterType:指定输入参数类型,MyBatis通过OGNL从输入对象中获取参数值设置在Sql中。
  2. resultType:指定输出结果类型,MyBatis将Sql查询结果的一行记录数据映射为resultType指定类型的 对象。

4.2 #{} 和 ${}

  1. #{}:
    1. #{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型、实体类类型、HashMap;
    2. #{}接收简单类型,#{}中可以写成value或其它名称;
    3. #{}接收实体类对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属 性值。
  2. ${}:
    1. 表示一个拼接符号,有 S q l 注入风险,所以不建议使用 {}表示一个拼接符号,有Sql注入风险,所以不建议使用 表示一个拼接符号,有Sql注入风险,所以不建议使用{};
    2. ${}接收输入参数,类型可以是简单类型、实体类类型、HashMap;
    3. 接收简单类型, {}接收简单类型, 接收简单类型,{}中只能写成value;
    4. ${}接收实体类对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属 性值。

4.2 selectOne和selectList

  1. selectOne表示查询出一条记录进行映射; 如果使用selectOne可以实现使用selectList也可以实现(list中只有一个对象)。
  2. selectList表示查询出一个列表(多条记录)进行映射; 如果使用selectList查询多条记录,不能使用selectOne。
  3. 如果使用selectOne报错:org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4

4.3 MyBatis和Hibernate区别

  1. Hibernate:是一个标准ORM框架(对象关系映射)。 入门门槛较高的,不需要程序写Sql,Sql语句自动生成,对Sql语句进行优化、修改比较困难的; 应用场景:适用与需求变化不多的中小型项目,比如:后台管理系统,erp、crm、oa…;
  2. MyBatis:专注于Sql本身,需要程序员自己编写Sql语句,Sql修改、优化比较方便。 MyBatis是一个不完全的ORM框架,虽然程序员自己写Sql,MyBatis也可以实现映射(输入映射、 输出映射); 应用场景:适用与需求变化较多的项目,比如:互联网项目;

4.4 Mybatis解决JDBC编程的问题

    1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问 题。
    2. 解决:在mybatis-config.xml中配置数据链接池,使用连接池管理数据库链接。
  1. Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变Java代码。
    1. 解决:将 Sql语句配置在XXXXmapper.xml文件中与Java代码分离。
  2. 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一 一 对应
    1. 解决:Mybatis自动将Java对象映射至sql语句,通过statement中的parameterType定义输入参数 的类型。
  3. 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo对象解析比较方便。
    1. 解决:Mybatis自动将sql执行结果映射至Java对象,通过statement中的resultType定义输出结果 的类型

5 Mybatis 开发 方式

5.1 DAO开发

  1. 原始DAO开发方式 : 编写Dao接口和Dao实现类,无非就是Dao实现类里面调用映射文件里面定 义的sql而已。
  2. 原始DAO开发问题 :
    1. Dao接口实现类方法中存在大量模板方法。每次都要创建。
    2. 由于SqlSession方法使用泛型,即使变量类型传入错误,在编 译阶段也不报错
    3. sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不利于开发维护。
 public class DeptDaoImpl implements DeptDao {@Overridepublic List<Dept> select() {SqlSession sqlSession = MybatisUtil.getSession();List<Dept> list = sqlSession.selectList("dept.select");sqlSession.close();return list;}@Overridepublic Dept selectById(Integer deptno) {SqlSession sqlSession = MybatisUtil.getSession();Dept dept = sqlSession.selectOne("dept.selectById", deptno);sqlSession.close();return dept;}}

5.2 Mybatis API

  1. SqlSessionFactoryBuilder: SqlSessionFactoryBuilder用于创建SqlSessionFacoty。
  2. SqlSessionFactory: SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法。
  3. SqlSession: SqlSession是一个面向用户(程序员)的接口,其中提供了很多操作数据库的方法。如: selectOne(返回单个对象)、selectList(返回单个或多个对象)、insert、update、delete。
    1. 但是 SqlSession的实现类不能共享,每次使用都要创建新的。

5.3 Mapper代理方式

  1. 只需要程序员编写Mapper接口(相当于Dao接口),由MyBatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
  2. 写Mapper接口遵循开发规范 , MyBatis可以自动生成Mapper接口实现类代理对象。
    1. Mapper.xml文件中的namespace与mapper接口的类路径相同。
    2. Mapper.xml中定义的每个标签的id与Mapper接口方法名相同。
    3. Mapper.xml中定义的每个sql的parameterType的类型与Mapper接口方法的参数类型相同。
    4. Mapper.xml中定义的每个sql的resultType的类型与Mapper接口方法返回值类型相同
  3. 新建一个实体类:
import java.util.Date;/*** Emp实体类
*/public class Emp {private Integer empno;private String ename;private String job;private Integer mgr;private Date hiredate;private Double sal;private Double comm;private Integer deptno;}

创建mapper接口:

package com.gs.mapper;* Mapper接口相当于我们之前写的Dao接口,只是在Mybatis里面我们习惯这么写而已。*/
public interface EmpMapper {List<Emp> select();Emp selectById(Integer empno);void insert(Emp emp);int update(Emp emp);boolean delete(Integer empno);}
1.  批量查询:方法返回值为List类型,表示SqlSession对象将调用selectList()方法。
2. 单条查询:方法返回值为单个实体对象,表示SqlSession对象将调用selectOne()方法。
3.  增删改: 1. 方法返回值为void,表示SqlSession对象中insert,update,delete方法的返回值不做任何处 理。 2. 方法返回值为int类型,表示SqlSession对象中insert,update,delete方法的返回值直接返 回3. 方法返回值为boolean类型,表示根据SqlSession对象中的insert,update,delete方法返回 值(影响数据库的条数)判断操作是否成功,如果影响数据库的条数大于0条,表示成功,否 则表示失败。  

编写mapper文件:

<?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">
<!--namespace:与Mapper接口的全限定名保持一致-->
<mapper namespace="com.gs.mapper.EmpMapper"><!--每个标签id与Mapper接口的方法名称保持一致;parameterType的类型必须与方法的参数类型保持一致;resultType的类型必须与方法的返回值类型保持一致;--><select id="select" resultType="com.gs.entity.Emp">select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp</select><select id="selectById" parameterType="java.lang.Integer" resultType="com.gs.entity.Emp">select empno,ename,job,hiredate,mgr,sal,comm,deptno from emp where empno=#{empno}</select><insert id="insert" parameterType="com.gs.entity.Emp">insert into emp(ename,job,mgr,hiredate,sal,comm,deptno)values(#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm},#{deptno})</insert><update id="update" parameterType="com.gs.entity.Emp">update emp setename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},sal=#{sal},comm=#{comm},deptno=#{deptno}where empno=#{empno}</update><delete id="delete" parameterType="java.lang.Integer">delete from emp where empno=#{empno}</delete>
</mapper>

在全局配置中加载该mapper文件

<!-- 加载映射文件的位置 --><mappers><mapper resource="mapper/EmpMapper.xml"/></mappers>

编写测试类:

public class MapperTest {private SqlSession sqlSession;private EmpMapper empMapper;@Before  //类加载之前执行的方法注解public void before() {sqlSession = MybatisUtil.getSession();//获取Mapper接口的代理对象empMapper = sqlSession.getMapper(EmpMapper.class);}@After //类加载之结束后执行的方法注解public void after() {sqlSession.commit();sqlSession.close();}@Testpublic void testSelect() {List<Emp> list = empMapper.select();for (Emp emp : list) {System.out.println(emp);}}@Testpublic void testSelectById() {Emp emp = empMapper.selectById(7938);System.out.println(emp);}@Testpublic void testInsert() {Emp emp = new Emp();emp.setEname("小明");emp.setJob("职员");emp.setSal(4500.0);emp.setComm(1000.0);emp.setMgr(1);emp.setHiredate(new Date());empMapper.insert(emp);}@Testpublic void testUpdate() {Emp emp = new Emp();emp.setEmpno(7940);emp.setEname("小李");emp.setJob("秘书");emp.setSal(5300.0);emp.setComm(1300.0);emp.setMgr(1);emp.setHiredate(new Date());int result = empMapper.update(emp);System.out.println("方法的返回值:" + result);}@Testpublic void testDelete() {boolean result = empMapper.delete(7940);System.out.println("方法的返回值:" + result);}
}

Mybatis官方推荐使用mapper代理方式开发mapper接口,程序员不用编写mapper接口实现类,使用 mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。

6 Mybatis 全局配置文件 mybatis-config.xml

6.1 配置内容如下

  1. properties(属性)
  2. settings(全局配置参数)
  3. typeAliases(类型别名)
  4. typeHandlers(类型处理器)
  5. objectFactory(对象工厂)
  6. plugins(插件)
  7. environments(环境集合属性对象)
  8. environment(环境子属性对象)
  9. transactionManager(事务管理)
  10. dataSource(数据源)
  11. mappers(映射器)

**上述的配置中各个标签可以不写,但顺序不能错!!! 具体可以参考 ****http://mybatis.org/dtd/mybatis-3-config.dtd ****文件 **

6.2 properties属性

将数据库连接参数单独配置在db.properties文件中,只需要在mybatis-config.xml中加载db.properties的属 性值。在mybatis-config.xml中就不需要对数据库连接参数硬编码。

d**b.properties**文件:

# Oracle相关配置
jdbc.oracle.driver=oracle.jdbc.driver.OracleDriver
jdbc.oracle.url=jdbc:oracle:thin:@localhost:1521:orcl
jdbc.oracle.username=scott
jdbc.oracle.password=tiger
# Mysql相关配置
jdbc.mysql.driver=com.mysql.jdbc.Driver
jdbc.mysql.url=jdbc:mysql://localhost:3306/ssm?
characterEncoding=utf8&useSSL=false
jdbc.mysql.username=root
jdbc.mysql.password=root

mybatis-config.xml中加载:

<!-- 加载外部资源文件 -->
<properties resource="db.properties"><!--properties中还可以配置一些属性--><!--<property name="mysql.url" value="jdbc:mysql://localhost:3306/ssm"/>--><environments default="mysql"><environment id="mysql"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${jdbc.mysql.driver}"/><property name="url" value="${jdbc.mysql.url}"/><property name="username" value="${jdbc.mysql.username}"/><property name="password" value="${jdbc.mysql.password}"/></dataSource></environment></environments>
</properties>

MyBatis将按照下面的顺序来加载属性。

  1. 在properties标签体内定义的属性首先被读取;
  2. 然后会读取properties标签中resource或url加载的属性,它会覆盖已读取的同名属性;
  3. 最后读取parameterType传递的属性,它会覆盖已读取的同名属性;

6.3 settings全局配置参数

  1. 可配置参数如下:
  2. 开启下划线与驼峰命名的转换:
settings><setting name="mapUnderscoreToCamelCase" value="true"/></settings>

6.4 typeAliases类型别名

  1. MyBatis默认支持别名

  1. 自定义别名 :
<typeAliases><typeAlias type="com.gs.entity.Dept" alias="dd"/> //alias:自定义的别名</typeAliases>
<typeAliases><package name="com.gs.entity"/>//package:批量设置别名 "com.gs.entity" 该包下的所有类的别名</typeAliases>
  1. 注解起别名 :
//使用注解@Alias("depart") 为类起别名。
@Alias("depart")
public class Dept {//...
}

注解和配置只能使用一种。

6.5 typeHandlers类型处理器

  1. MyBatis支持的类型处理器:

MyBatis中通过typeHandlers完成JDBC类型和Java类型的转换,MyBatis自带的类型处理器基本上满足 日常需求,不需要单独定义。

6.6 mappers映射器

  1. 单个加载映射文件
<mappers><!--<mapper>单个加载映射文件;resource:通过相对路径加载文件(mapper目录);url:通过绝对路径加载文件(文件系统中文件);--><mapper resource="mapper/DeptMapper.xml"/><mapper resource="mapper/EmpMapper.xml"/><!-- 通过类的全名 --><mapper class="com.gs.mapper.EmpMapper"/>
</mappers>

要求:

1. 必须使用mapper代理的开发方式;
2. mapper.xml文件的名称必须与dao接口的名称保持一致;
3. mapper.xml文件必须与dao接口放在同一个目录下;
1.  批量加载映射文件  
  1. 批量加载映射文件 :
<mappers><!--<package>批量加载映射文件
name:存放Mapper接口与mapper.xml文件的包名--><package name="com.gs.mapper"/></mappers>

此种配置使mapper扫描指定包,并在此包下获取所有的接口以及与接口名称相同mapper文件, 并加载;

7 Mybatis mapper配置文件 mapper.xml

mapper.xml映射文件中定义了操作数据库的Sql,每个Sql是一个statement(陈述),映射文件是MyBatis的核 心

7.1 输入映射

  1. resultType输出映射 : 配置输入参数的类型 。
  2. resultType输出映射 :配置输出参数的类型 。
<?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.gs.mapper.UsersMapper"><select id="selectByRealname" parameterType="java.lang.String" resultType="com.gs.entity.Users">select id,username,password,realname from users where realname like concat('%',#{realname},'%')</select></mapper>

7.2 通过实体类或pojo类型传递查询条件

  1. 自定义创建的类,或者复合类。
  2. 在mapper接口实现方法类:
List<Users> selectByPage(Page page);
// 符合类
List<Users> selectByRealnameAndPage(UsersQuery usersQuery);
// 多个参数输入
Users login(@Param("uname") String username, @Param("pwd") String password);
// map集合类
List<Users> selectUseMap(Map<String, Object> map);
  1. 编写mapper.xml文件
<select id="selectByPage" parameterType="com.gs.entity.Page" resultType="com.gs.entity.Users">select id,username,password,realname from users order by id limit #{offset}, #{pageSize}
</select><select id="selectByRealnameAndPage" parameterType="com.gs.entity.UsersQuery" resultType="com.gs.entity.Users">select id,username,password,realname from userswhere realname like concat('%',#{users.realname},'%')order by id limit #{page.offset}, #{page.pageSize}
</select><select id="selectUseMap" parameterType="java.util.HashMap" resultType="com.gs.entity.Users">select id,username,password,realname from userswhere realname like concat('%',#{name},'%')order by id limit #{begin}, #{size}</select><select id="login" parameterType="java.util.HashMap" resultType="com.gs.entity.Users">select id,username,password,realname from userswhere username=#{uname} and password=#{pwd}</select>

7.3 resultMap 与 resultType

  • resultType: 自动映射。
  • resultMap: 手动映射。1.可以实现将查询结果映射为复合型的实体类,比如在查询结果映射对象中包括实体类和 list实现一对一查询和一对多查询。 2. 果SQL查询字段名和实体类的属性名不一致,可以通过resultMap将字段名和属性名作一个对应 关系,resultMap实质上还会将查询结果映射到实体类对象中。
    • id: 唯一标识,名称; type: 手动映射的java类型;
    • 子标签 配置数据库表中的主键和实体类中属性的对应关系;
    • 子标签 配置数据库表中的普通字段和实体类中属性的对应关系;
      • property:实体类中的成员变量名;
      • column:结果集中的字段名称;
      • javaType:实体类成员变量的类型,由mybaits自动识别,可不配置;
      • jdbcType:表字段的类型,由mybaits自动识别,可不配置;
      • typeHandler:自定义类型处理器,用的相对比较少;
<resultMap id="selectResultMap" type="com.gs.entity.Person"><id property="id" column="id"/><result property="personName" column="person_name"/><result property="personAge" column="person_age"/><result property="personAddress" column="person_address"/></resultMap><select id="select" resultMap="selectResultMap">select id,person_name,person_age,person_address from person</select>

7.4 动态SQL

简单来说。就是对sql语句添加动态的条件。

  1. if标签
 <select id="selectUseIf" parameterType="com.gs.entity.Emp" resultType="com.gs.entity.Emp">select empno,ename,job,mgr,hiredate,sal,comm,deptno from empwhere<!--注意:判断条件中使用的变量为实体类或输入参数的属性空字符串的判断仅能使用在字符串类型的属性中--><if test="ename != null and ename != ''">ename like concat('%',#{ename},'%')</if><if test="sal != null">and sal=#{sal}</if><if test="deptno != null">and deptno=#{deptno}</if></select>
  1. where标签
 <select id="selectUseWhere" parameterType="com.gs.entity.Emp"  resultType="com.gs.entity.Emp">select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp<where><if test="ename != null and ename != ''">ename like concat('%',#{ename},'%')</if><if test="sal != null">and sal=#{sal}</if><if test="deptno != null">and deptno=#{deptno}</if></where></select>
  1. set标签
    1. 当set标签内所有的条件都不成立,不会拼接set关键字,只要有一个条件成立就会在SQL语句中拼
      接set关键字。注意:如果set包含的内容为空SQL语句会出错。
    2. set标签会自动剔除条件末尾的任何不相关的逗号。
<update id="updateUseSet" parameterType="com.gs.entity.Emp">update emp<set><if test="ename != null">ename=#{ename},</if><if test="hiredate != null">hiredate=#{hiredate},</if><if test="sal != null">sal=#{sal},</if><if test="comm != null">comm=#{comm},</if><if test="deptno != null">deptno=#{deptno},</if></set>where empno=#{empno}</update>
  1. foreach标签 : 向SQL传递数组或list,MyBatis使用foreach解析。
    1. collection: 遍历的数组或集合对象名称。
      1. SQL只接收一个数组参数,这时SQL解析参数的名称MyBatis固定为array。
      2. SQL只接收一个List参数,这时SQL解析参数的名称MyBatis固定为list。
      3. 如果是通过一个实体类或自定义类型的属性传递到SQL的数组或List集合,则参数的名称为实 体类或自定义类型中的属性名。
    2. index: 为数组的下标。
    3. item: 每次遍历生成的对象。
    4. open: 开始遍历时拼接的串。
    5. close: 结束遍历时拼接的串。
    6. separator: 遍历的两个对象中需要拼接的串。
<delete id="deleteUseForeach" parameterType="java.lang.Integer"><!--delete from emp where empno in (1,2,3,4)-->delete from emp where empno in<foreach collection="array" open="(" close=")" separator="," item="id">#{id}</foreach></delete><insert id="insertUseForeach" parameterType="com.gs.entity.Emp">insert into emp(ename,job,mgr,hiredate,sal,comm,deptno) values<foreach collection="list" separator="," item="emp">(#{emp.ename},#{emp.job},#{emp.mgr},#{emp.hiredate},#{emp.sal},# {emp.comm},#{emp.deptno})</foreach></insert>
  1. choose标签 : choose标签、when标签、otherwise标签的组合,类似于if-else-if判断。
<select id="">select...<choose><when test=""></when><when test=""></when><otherwise></otherwise></choose></select>
  1. SQL片段 :将重复的sql语句封装起来给其他语句使用。片段, 通过 签就可以引用SQL片段
<sql id="feildSql">empno,ename,job,mgr,hiredate,sal,comm,deptno</sql><include><sql id="whereSql"><if test="ename != null and ename != ''">ename like concat('%',#{ename},'%')</if><if test="sal != null">and sal=#{sal}</if><if test="deptno != null">and deptno=#{deptno}</if></sql><select id="selectUseSql" parameterType="com.gs.entity.Emp" resultType="com.gs.entity.Emp">select<include refid="feildSql"></include>from emp<where><include refid="whereSql"></include></where></select>

7.5 Map输入和输出类型

  1. Mapper接口:
public interface DeptMapper {//查询List<Map<String, Object>> queryAllDept();//插入int insertDept(Map<String, Object> map);
}
  1. Mapper文件:
<!--
查询,输出参数是Map
Mybatis会把查询结果给我们封装成List<Map>
因为一行数据就是一个Map-->
<select id="queryAllDept" resultType="hashmap">select * from dept
</select>
<!--插入,输入参数是Map-->
<!--输入参数是hashmap,那么#{map中的key}-->
<insert id="insertDept" parameterType="hashmap">insert into dept values (#{id},#{name},#{address})
</insert>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/62845.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HNTS-MRG 2024 Challenge:是一个包含200个头颈癌病例的磁共振图像及其标注的公开数据集,旨在推动AI在头颈癌放射治疗自动分割领域的研究。

2024-11-28,由德克萨斯大学MD安德森癌症中心创建HNTS-MRG 2024 Challenge数据集&#xff0c;目的通过公开数据集推动自动分割算法的发展&#xff0c;这对于提高放射治疗的精确性和效率具有重要意义。 数据集地址&#xff1a;HNTS-MRG 2024|癌症放射治疗数据集|医学影像分析数据…

【python】OpenCV—Tracking(10.5)—dlib

文章目录 1、功能描述2、代码实现3、效果展示4、完整代码5、涉及到的库函数dlib.correlation_tracker() 6、参考 1、功能描述 基于 dlib 库&#xff0c;实现指定类别的目标检测和单目标跟踪 2、代码实现 caffe 模型 https://github.com/MediosZ/MobileNet-SSD/tree/master/…

探索温度计的数字化设计:一个可视化温度数据的Web图表案例

随着科技的发展&#xff0c;数据可视化在各个领域中的应用越来越广泛。在温度监控和展示方面&#xff0c;传统的温度计已逐渐被数字化温度计所取代。本文将介绍一个使用Echarts库创建的温度计Web图表&#xff0c;该图表通过动态数据可视化展示了温度值&#xff0c;并通过渐变色…

20241128解决Ubuntu20.04安装libwxgtk3.0-dev异常的问题

20241128解决Ubuntu20.04安装libwxgtk3.0-dev异常的问题 2024/11/28 16:17 缘起&#xff1a;中科创达的高通CM6125开发板的Android10的编译环境需要。 安装异常&#xff1a;rootrootrootroot-X99-Turbo:~$ rootrootrootroot-X99-Turbo:~$ sudo apt-get install libwxgtk3.0-de…

大疆T100大载重吊运植保无人机技术详解

大疆T100作为一款大载重吊运植保无人机&#xff0c;融合了全新的AI和AR功能&#xff0c;旨在进一步提升安全性并满足喷洒、播撒、吊运等多种作业场景的需求。以下是对其技术的详细解析&#xff1a; 一、总体性能 最大起飞重量&#xff1a;149.9公斤 喷洒容量&#xff1a;75升…

arkTS:使用ArkUI实现用户信息的持久化管理与自动填充(PersistentStorage)

arkUI&#xff1a;使用ArkUI实现用户信息的持久化管理与自动填充&#xff08;PersistentStorage&#xff09; 1 主要内容说明2 例子2.1 登录页2.1.1登陆页的相关说明2.1.1.1 持久化存储的初始化2.1.1.2 输入框2.1.1.3 记住密码选项2.1.1.4 登录按钮的逻辑2.1.1.5 注册跳转 2.1.…

腾讯云 AI 代码助手:单元测试应用实践

引言 在软件开发这一充满创造性的领域中&#xff0c;开发人员不仅要构建功能强大的软件&#xff0c;还要确保这些软件的稳定性和可靠性。然而&#xff0c;开发过程中并非所有任务都能激发创造力&#xff0c;有些甚至是重复且乏味的。其中&#xff0c;编写单元测试无疑是最令人…

1、Three.js开端准备环境

准备工作 从 CDN 导入 1.安装 VSCode 2.安装 Node.js 3.查看Three.js最新版本 4.如何cdn引入&#xff1a; https://cdn.jsdelivr.net/npm/threev版本号/build/three.module.js 例如&#xff1a;https://cdn.jsdelivr.net/npm/threev0.170.0/build/three.module.js 我们需要…

Python毕业设计选题:基于django+vue的校园影院售票系统

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 管理员登录 管理员功能界面 用户管理 影院信息管理 电影类型管理 电影信息管理 系统…

初窥 HTTP 缓存

引言 对于前端来说, 你肯定听说过 HTTP 缓存。 当然不管你知不知道它, 对于提高网站性能和用户体验, 它都扮演着重要的角色! 它通过在客户端和服务器之间存储和重用先前获取的资源副本, 来减少网络流量和降低资源加载时间, 从而提升用户体验! 以下是 HTTP 缓存的重要性: 减少…

Django 视图层

from django.shortcuts import render, HttpResponse, redirectfrom django.http import JsonResponse1. render: 渲染模板 def index(request):print(reverse(index))return render(request, "index.html")return render(request, index.html, context{name: lisi})…

简单介绍下 VitePress 中的 vp-doc 和 vp-raw

VitePress 是一个轻量级的静态网站生成器&#xff0c;专为快速构建文档网站而设计。它是基于 Vite 和 Vue 3 构建的&#xff0c;旨在提供快速的开发体验和高效的构建过程。 存在两个需要注意的点&#xff1a;vp-doc 和 vp-raw&#xff0c;它们代表了不同的 CSS 样式类和用途&a…

【数据结构】LinkedList与链表

LinkedList与链表 1. ArrayList的缺陷2. 链表2.1 链表的概念及结构2.2 链表的实现 3.链表面试题 【本节目标】 ArrayList的缺陷链表链表相关ojLinkedList的模拟实现LinkedList的使用ArrayList和LinkedList的区别 1. ArrayList的缺陷 上节课已经熟悉了ArrayList的使用&#xf…

Matrix Multiplication

lab要求如下&#xff1a;

Laravel8.5+微信小程序实现京东商城秒杀方案

一、商品秒杀涉及的知识点 鉴权策略封装掊口访问频次限制小程序设计页面防抖接口调用订单创建事务使用超卖防御 二、订单库存系统方案&#xff08;3种&#xff09; 下单减库存 优点是库存和订单的强一致性&#xff0c;商品不会卖超&#xff0c;但是可能导致恶意下单&#xff…

esp8266 编译、烧录环境搭建

一、准备 xtensa-lx106-elf-gcc8-4-0-esp-2020r3-win32下载&#xff1a;点击跳转 MSYS2 压缩包文件&#xff1a; 固件烧录工具&#xff1a;点击跳转 esp8266源码地址&#xff1a;点击跳转 二、搭建编译环境 1、在D盘创建一个ESP8266目录&#xff0c;解压MSYS2.zip到里面&a…

WEB攻防-通用漏洞CSRFSSRF协议玩法内网探针漏洞利用

CSRF构造工具&#xff0c;也可以用bp构造 选中要保存的请求&#xff0c;点击Generate HTML,生成带有添加用户请求的html文件&#xff0c;然后将构造的html放在网站上&#xff0c;生成访问地址&#xff0c;诱导管理员点击链接&#xff0c;就会添加用户 start Recording之后就会…

2-7 C函数指针与回调函数

前言&#xff1a; 对函数指针与回调函数知识回顾&#xff0c;仅供学习参考... 目录 前言&#xff1a; 1.0 函数指针 2.0 函数指针变量 3.0 函数指针与指针函数 4.0 函数指针类型 5.0 卡点 后记&#xff1a; 1.0 函数指针 函数指针&#xff0c;简单来说就是指向函数的指针…

分布式FastDFS存储的同步方式

目录 一&#xff1a;FatsDFS的结构图 二&#xff1a;FatsDFS文件同步 前言&#xff1a; 1&#xff1a;同步日志所在目录 2&#xff1a;binlog格式 3&#xff1a;同步规则 4&#xff1a;binlog同步过程 1 &#xff1a;获取组内的其他Storage信息 tracker_report_thread_e…

【大模型】ChatGPT 提示词优化进阶操作实战详解

目录 一、前言 二、ChatGPT 提示词几个基本的优化原则 2.1 明确的提示词 2.1.1 提示词具体而清晰 2.1.1.1操作案例演示 2.2 确定焦点 2.2.1 操作案例演示 2.3 保持提示词的相关性 2.3.1 什么是相关性 2.3.2 提示词相关性操作案例一 2.3.2 提示词相关性操作案例二 三…