12-mybatis框架 unit12-mybatis框架
a0a2eb9fa872009998f7cd818925095d
课程计划:
1、MyBatis快速入门
2、MyBatis对数据库中数据的增删改查操作
3、#{}占位符的应用
4、动态SQL的应用
5、MyBatis的Mapper接口开发
MyBatis简介(了解) 什么是MyBatis MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
总之,Mybatis对JDBC访问数据库的过程进行了封装,简化了JDBC代码,解决JDBC将结果集封装为Java对象的麻烦。
下图是MyBatis架构图:
f6d67734982f864da415a2a9cc4908a5
(1)mybatis-config.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂
(2)基于SqlSessionFactory可以生成SqlSession对象
(3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。
(4)Executor是SqlSession底层的对象,用于执行SQL语句
(5)MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)
为什么要使用MyBatis 思考:在开始之前,思考下如何通过JDBC查询Emp表中的所有记录,并封装到一个List集合中返回。(演示:准备数据、导包、导入JDBC程序)
1、使用传统方式JDBC访问数据库:
(1)使用JDBC访问数据库有大量重复代码(比如注册驱动、获取连接、获取传输器、释放资源等);
(2)JDBC自身没有连接池,会频繁的创建连接和关闭连接,效率低;
(3)SQL是写死在程序中,一旦修改SQL,需要对类重新编译;
(4)对查询SQL执行后返回的ResultSet对象,需要手动处理,有时会特别麻烦;
…
2、使用mybatis框架访问数据库:
(1)Mybatis对JDBC对了封装,可以简化JDBC代码;
(2)Mybatis自身支持连接池(也可以配置其他的连接池),因此可以提高程序的效率;
(3)Mybatis是将SQL配置在mapper文件中,修改SQL只是修改配置文件,类不需要重新编译。
(4)对查询SQL执行后返回的ResultSet对象,Mybatis会帮我们处理,转换成Java对象。
…
总之,JDBC中所有的问题(代码繁琐、有太多重复代码、需要操作太多对象、释放资源、对结果的处理太麻烦等),在Mybatis框架中几乎都得到了解决!!
MyBatis快速入门 准备数据,创建库和表 创建yonghedb库、emp表,并插入若干条记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 create database if not exists yonghedb charset utf8;use yonghedb; drop table if exists emp;create table emp( id int primary key auto_increment, name varchar (50 ), job varchar (50 ), salary double ); insert into emp values (null , '王海涛' , '程序员' , 3300 );insert into emp values (null , '齐雷' , '程序员' , 2800 );insert into emp values (null , '刘沛霞' , '程序员鼓励师' , 2700 );insert into emp values (null , '陈子枢' , '部门总监' , 4200 );insert into emp values (null , '刘昱江' , '程序员' , 3000 );insert into emp values (null , '董长春' , '程序员' , 3500 );insert into emp values (null , '苍老师' , '程序员' , 3700 );insert into emp values (null , '韩少云' , 'CEO' , 5000 );
创建工程,导入所需jar包、创建测试类 1、创建Maven的java工程
313e2677abaf6d235c0f8603165739fc
2、导入junit、mysql、mybaits等开发包
在pom.xml文件中引入相关依赖包即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <dependencies > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.9</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.32</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.2.8</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-log4j12</artifactId > <version > 1.6.4</version > </dependency > </dependencies >
3、创建com.tedu.mybatis.TestMybatis01测试类,并提供findAll方法(查询emp表中所有的员工信息),开发步骤如下:
image-20200403151610907
1 2 3 4 5 6 7 8 9 10 @Test public void findAll () throws IOException { }
添加mybatis-config.xml文件 1、在src/main/resources目录下,创建mybatis-config.xml文件 (MyBatis的核心配置文件)
3e84b2af713f0ddea7c6164f57806c60
2、mybatis-config.xml文件配置如下:
mybatis-config文件头信息如下:
1 2 3 4 5 6 7 8 9 <?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 > </configuration >
mybatis-config文件详细配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <?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 ="develop" > <environment id ="develop" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="EmpMapper.xml" /> </mappers > </configuration >
添加EmpMapper.xml文件 1、在src/main/resources目录下,创建EmpMapper.xml文件 (实体类的映射文件)
bf0e887dec06ea62dbad0673fe4b2730
2、EmpMapper.xml文件配置如下:
EmpMapper文件头信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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 ="" > </mapper >
EmpMapper文件详细配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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 ="EmpMapper" > <select id ="findAll" resultType ="com.tedu.pojo.Emp" > select * from emp </select > </mapper >
添加并编写Emp实体类 注意:在当前实例中,Emp类中的属性和数据库表的字段名称必须一致,否则将会无法将结果集封装到Java对象中。
在src/main/java目录下创建 com.tedu.pojo.Emp类,并编辑Emp类:提供私有属性以及对应的getter方法、setter方法,并重写toString方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package com.tedu.pojo;public class Emp { private Integer id; private String name; private String job; private Double salary; 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 String getJob () { return job; } public void setJob (String job) { this .job = job; } public Double getSalary () { return salary; } public void setSalary (Double salary) { this .salary = salary; } @Override public String toString () { return "Emp [id=" + id + ", name=" + name + ", job=" + job + ", salary=" + salary + "]" ; } }
实现测试类,并测试 1、实现findAll方法,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Test public void findAll () throws IOException { InputStream in = Resources .getResourceAsStream("mybatis-config.xml" ); SqlSessionFactory fac = new SqlSessionFactoryBuilder().build( in ); SqlSession session = fac.openSession(); List<Emp> list = session .selectList("EmpMapper.findAll" ); for (Emp e : list) { System.out.println( e ); } }
2、执行findAll方法,输出结果为:
1 2 3 4 5 6 7 8 Emp [id=1, name=王海涛, job=程序员, salary=3300.0] Emp [id=2, name=齐雷, job=程序员, salary=2800.0] Emp [id=3, name=刘沛霞, job=程序员鼓励师, salary=2700.0] Emp [id=4, name=陈子枢, job=部门总监, salary=4200.0] Emp [id=5, name=刘昱江, job=程序员, salary=3000.0] Emp [id=6, name=董长春, job=程序员, salary=3500.0] Emp [id=7, name=苍老师, job=程序员, salary=3700.0] Emp [id=8, name=韩少云, job=CEO, salary=5000.0]
MyBatis入门细节 mybatis-config.xml配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <?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 ="develop" > <environment id ="develop" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="EmpMapper.xml" /> </mappers > </configuration >
environments
标签:该标签内部可以配置多个environment,即多种环境,每种环境可以做不同配置或连接不同数据库。例如,开发、测试、生产环境可能需要不同的配置,连接的数据库可能也不相同,因此我们可以配置三个environment,分别对应上面三种不同的环境。
但是要记住,environment可以配置多个,但是最终要使用的只能是其中一个!
environment
标签:内部可以配置多种配置信息,下面介绍事务管理配置和数据源配置。
transactionManage
标签:事务管理配置,mybatis中有两种事务管理方式,也就是
type=”[JDBC|MANAGED]。
1 2 JDBC:这个配置就是直接使用了 JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围。推荐使用。 MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。需要自己手动添加并管理。不推荐使用。
dataSource
标签:数据源,也就是连接池配置。这里type指定数据源类型,有三种内建的类型:JNDI、POOLED、UNPOOLED
1 2 3 JNDI:已过时,不推荐使用! POOLED:使用连接池,mybatis会创建连接池,并从连接池中获取连接访问数据库,在操作完成后,将会把连接返回连池。 UNPOOLED:不使用连接池,该方式适用于只有小规模数量并发用户的简单应用程序上。
mappers
标签:用于导入mapper文件的位置,其中可以配置多个mapper,即可以导入多个mapper文件。
EmpMapper.xml配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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 ="EmpMapper" > <select id ="findAll" resultType ="com.tedu.pojo.Emp" > select * from emp </select > </mapper >
(1)第1行是xml的文档声明,用于声明xml的版本和编码
(2)第2、3、4行,引入了xml约束文档,当前xml文档将会按照mybatis-3-mapper.dtd文件所要求的规则进行书写。
(3)Mapper标签:根标签,其中namespace(名称空间,也叫命名空间),要求不能重复。在程序中通过【namespace + id 】定位到要执行哪一条SQL语句
(4)select标签:用于指定将来要执行的各种SQL语句。标签上可以声明属性,下面介绍常用的属性:id、resultType、resultMap
id属性:要求值不能重复。将来在执行SQL时,可以通过【namespace + id】找到指定SQL并执行。
resultType属性:从这条SQL语句中返回所期望类型的类的完全限定名称(包名+类名)。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。
简而言之,resultType控制查询SQL执行后返回值的类型或集合中的泛型,例如查询emp表中的单条记录,返回值是一个Emp对象,因此,resultType=”com.tedu.pojo.Emp”;
如果查询emp表中的多条记录,返回值是一个List,此时resultType的值应该集合中的泛型,因此resultType=”com.tedu.pojo.Emp”;
resultMap属性:复杂对象结构(例如多表关联查询等)。 使用 resultType 或 resultMap,但不能同时使用。
MyBatis增删改查 新增员工 1、编辑EmpMapper.xml文件, 添加新增员工对应的sql.
1 2 3 4 5 6 <update id ="insert" > insert into emp value(null, '赵云', '保安', 6000) </update >
2、编写TestMybatis类,添加testInsert方法,实现新增员工操作。
1 2 3 4 5 6 7 8 9 @Test public void testInsert () { int rows = session.update("EmpMapper.insert" ); session.commit(); System.out.println("影响的行数: " +rows); }
修改员工 1、编辑EmpMapper.xml文件, 添加新增员工对应的sql。
1 2 3 4 <update id ="update" > update emp set job='保镖', salary=20000 where name='赵云' </update >
2、编写TestMybatis类,添加testUpdate方法,实现修改员工信息。
1 2 3 4 5 6 7 8 9 @Test public void testUpdate () { int rows = session.update("EmpMapper.update" ); session.commit(); System.out.println("影响行数:" +rows); }
删除员工 1、编辑EmpMapper.xml文件, 添加新增员工对应的sql。
1 2 3 4 <update id ="delete" > delete from emp where name='赵云' </update >
2、编写TestMybatis类,添加 testDelete方法,实现删除员工。
1 2 3 4 5 6 7 8 9 @Test public void testDelete () { int rows = session.update("EmpMapper.delete" ); session.commit(); System.out.println("影响行数:" +rows); }
mybatis中的占位符 #{}占位符 在上面的增删改查操作中,SQL语句中的值是写死在SQL语句中的,而在实际开发中,此处的值往往是用户提交过来的值,因此这里我们需要将SQL中写死的值替换为占位符。
在mybatis中占位符有两个,分别是 #{}
占位符 和 ${}
占位符:
#{}:
相当于JDBC中的问号(?)占位符,是为SQL语句中的参数值进行占位,大部分情况下都是使用#{}占位符; 并且当#{}占位符是为字符串或者日期类型的值进行占位时,在参数值传过来替换占位符的同时,会进行转义处理(在字符串或日期类型的值的两边加上单引号)
${}
:是为SQL片段进行占位,将传过来的SQL片段直接拼接在${}占位符所在的位置,不会进行任何的转义处理。(由于是直接将参数拼接在SQL语句中,因此可能会引发SQL注入攻击问题)
练习5:查询emp表中指定id的员工信息
在mapper文件中编写SQL语句:
1 2 3 4 <select id ="findById" resultType ="com.tedu.pojo.Emp" > select * from emp where id=#{id} </select >
Java代码实现:
1 2 3 4 5 6 7 @Test public void testFindById () { Emp emp = session.selectOne( "EmpMapper.findById" , 1 ); System.out.println( emp ); }
练习6:新增员工信息: 张飞 Java开发工程师 15000
在mapper文件中编写SQL语句:
1 2 3 4 5 6 7 8 9 10 <update id ="insert2" > insert into emp values (null, #{name}, #{job}, #{salary}) </update >
Java代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Test public void testInsert2 () { Emp emp = new Emp(); emp.setName("关羽123" ); emp.setJob("保安" ); emp.setSalary(8000.0 ); intsession rows = session.update("EmpMapper.insert2" , emp); session.commit(); System.out.println( "影响的行数: " +rows ); }
练习7:修改员工信息: 张飞 架构师 25000
在mapper文件中编写SQL语句:
1 2 3 4 5 <update id ="update2" > update emp set job=#{job}, salary=#{salary} where name=#{name} </update >
Java代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void testUpdate2 () { Emp emp = new Emp(); emp.setName("张飞" ); emp.setJob("架构师" ); emp.setSalary(25000.0 ); intsession rows = session.update("EmpMapper.update2" , emp); session.commit(); System.out.println("影响的行数: " +rows); }
练习8:删除emp表中指定id的员工信息
mapper文件配置:
1 2 3 4 <insert id ="delete2" parameterType ="String" > delete from emp where id=#{id} </insert >
java代码示例:
1 2 3 4 5 6 7 8 9 public void testDelete2 () throws IOException { ...... int rows = session.delete("EmpMapper.delete2" , 1 ); session.commit(); System.out.println("影响行数:" +rows); }
在上面的增删改查练习中,当SQL语句中包含的参数值是传递过来的,在SQL语句中我们会通过#{}
占位符进行占位,在SQL语句真正执行时,再将传递过来的值替换SQL语句中的占位符。
其实,#{}
就是JDBC中的问号(? )占位符,因此为了安全考虑,在执行时会对传递过来的字符串和日期类型高的值进行转译处理。
例如:查询指定name的员工信息,SQL语句为:
1 select * from emp where name =
其实就等价于JDBC中: select * from emp where name=?
,
如果传过来的参数值为:王海涛,那么最终执行的SQL语句为:
1 2 select * from emp where name ='王海涛'
${}占位符 那么如果我们在传递的时候不是一个参数值,而是一个SQL片段呢?
例如:在查询时,我们想动态的传递查询的列:
此时传递过来的应该是一个SQL片段,不同于上面的参数值,如果此时还用#{}
,也会像上面一样被转译处理:select 'id,name,job' from emp
,这不是我们希望看到的!
如果不想让传过来的SQL片段被转译处理,而是直接拼接在SQL语句中,那么这里可以使用${}
,例如:
1 select ${columns } from emp
拼接之后:select id,name,job from emp
练习9:动态指定要查询的列
在mapper文件中编写SQL语句:
1 2 3 4 <select id ="findAll2" resultType ="com.tedu.pojo.Emp" > select ${cols} from emp </select >
java代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void testFindAll2 () { Map map = new HashMap(); map.put("cols" , "id,name,job,salary" ); List<Emp> list = session.selectList("EmpMapper.findAll2" , map); for ( Emp e : list ) { System.out.println( e ); } }
示例2: 根据name模糊查询emp表
在mapper文件中编写SQL语句:
1 2 3 4 5 <select id ="findAll3" resultType ="com.tedu.pojo.Emp" > select * from emp where name like '%${name}%' </select >
1 2 3 4 5 <select id ="findAll4" resultType ="com.tedu.pojo.Emp" > select * from emp where name like #{name} </select >
Java代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void testFindAll3 () { Map map = new HashMap(); map.put("name" , "涛" ); List<Emp> list = session.selectList("EmpMapper.findAll3" , map); for (Emp emp : list) { System.out.println( emp ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void testFindAll4 () { Map map = new HashMap(); map.put("name" , "%刘%" ); List<Emp> list = session.selectList("EmpMapper.findAll4" , map); for (Emp emp : list) { System.out.println( emp ); } }
需要注意的是,在传递 ${}
对应的值时,即使只有一个参数,也需要将值存入map 集合中!!
总结:在大多数情况下还是使用#{}占位符,而${}多用于为SQL片段进行占位!
动态SQL标签 if、where标签
f06a2a2de234a540b189b15d65943989
练习12:根据薪资查询员工信息(if标签)
<if>
标签:是根据test属性
中的布尔表达式的值,从而决定是否执行包含在其中的SQL片段。如果判断结果为true,则执行其中的SQL片段;如果结果为false,则不执行其中的SQL片段
在mapper文件中编写SQL语句:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <select id ="findAllBySal" resultType ="com.tedu.pojo.Emp" > select * from emp where 1=1 <if test ="minSal != null" > and salary>#{minSal} </if > <if test ="maxSal != null" > and salary <![CDATA[ < ]]> #{maxSal} </if > </select >
Java代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Test public void testFindBySal () { Map<String, Object> map = new HashMap<String, Object>(); List<Emp> list = session.selectList( "EmpMapper.findBySal" , map ); for (Emp emp : list) { System.out.println( emp ); } }
练习13:根据薪资查询员工信息(where标签)
<where>
标签:用于对包含在其中的SQL片段进行检索,在需要时可以生成where关键字,并且在需要时会剔除多余的连接词(比如and或者or)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <select id ="findAllBySal2" resultType ="com.tedu.pojo.Emp" > select * from emp <where > <if test ="minSal != null" > and salary>#{minSal} </if > <if test ="maxSal != null" > and salary <![CDATA[ < ]]> #{maxSal} </if > </where > </select >
Java代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Test public void testFindAllBySal () { Map map = new HashMap(); map.put("minSal" , 3000 ); map.put("maxSal" , 4000.0 ); List<Emp> list = session.selectList("EmpMapper.findAllBySal2" , map); for (Emp emp : list) { System.out.println( emp ); } }
foreach元素 foreach标签:可以对传过来的参数数组或集合进行遍历,以下是foreach标签上的各个属性介绍:
属性
属性描述
collection
必需,值为遍历的集合类型,例如:如果参数只是一个数组或List集合,则collection的值为array或list;如果传的是多个参数,用map封装,collection则指定为map中的key。
item
必需,若collection为数组或List集合时,item表示其中的元素,若collection为map中的key,item表示map中value(集合或数组)中的元素
open
可选,表示遍历生成的SQL片段以什么开始,最常用的是左括号’(‘
close
可选,表示遍历生成的SQL片段以什么结束,最常用的是右括号’)’
separator
可选,每次遍历后给生成的SQL片段后面指定间隔符
练习14: 根据员工的id批量删除员工信息
在mapper文件中编写SQL语句:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <delete id ="deleteByIds" > delete from emp where id in <foreach collection ="array" open ="(" item ="id" separator ="," close =")" > #{id} </foreach > </delete >
Java代码实现:
1 2 3 4 5 6 7 8 @Test public void testDeleteByIds () { Integer[] ids = {1 ,3 ,5 ,7 }; int rows = session.delete( "EmpMapper.deleteByIds" , ids ); System.out.println( "影响行数: " +rows ); }
练习15:根据员工的id批量更新员工信息
在mapper文件中编写SQL语句:
1 2 3 4 5 6 7 8 9 10 11 12 <update id ="updateByIds" > update emp set salary=salary + #{sal} where id in <foreach collection ="arrIds" open ="(" item ="id" separator ="," close =")" > #{id} </foreach > </update >
Java代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void testUpdateByIds () { Integer[] ids = {2 ,4 ,6 ,8 }; Double sal = 1000.0 ; Map<String, Object> map = new HashMap<String, Object>(); map.put( "arrIds" , ids ); map.put( "sal" , sal ); int rows = session.update( "EmpMapper.updateByIds" , map ); System.out.println( "影响行数: " +rows ); }
下面练习自己完成:
1 2 3 4 5 @Test public void testFindByIds () {}
Mapper接口开发 Mapper接口开发介绍 在上面的Mybatis案例中, 通过SqlSession对象调用方法进行增删改查操作时,方法中需要传入的第一个参数是一个字符串值,该值对应的内容为: (Mapper文件中的)namespace + id, 通过这种方式,找到Mapper文件中映射的SQL语句并执行!!
这种方式由于传入的是字符串值, 很容易发生字符串拼写错误且编译时期不会提示。
这里我们将会讲解比上面更加简单的方式,也是我们企业开发中最常用的方式,即使用mapper接口开发。使用mapper接口开发需要注意以下几点:
1 2 3 4 1、创建一个接口,接口的全路径名和mapper文件的namespace值要相同 2、mapper文件中每条要执行的SQL语句,在接口中要添加一个对应的方法,并且接口中的方法名和SQL标签上的id值相同 3、Mapper接口中方法接收的参数类型,和mapper.xml中定义的sql的接收的参数类型要相同 4、接口中方法的返回值类型和SQL标签上的resultType即返回值类型相同(如果方法返回值是集合,resultType只需要指定集合中的泛型)
Mapper接口开发实现 下面将使用mapper接口开发的方式,实现根据id查询指定的员工信息
1、创建com.tedu.dao.EmpMapper接口
由于接口的全路径名(com.tedu.dao.EmpMapper)要和EmpMapper.xml的namespace值保持一致,因此, 这里将namespace的值改为com.tedu.dao.EmpMapper:
1 2 3 4 5 6 7 <?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.tedu.dao.EmpMapper" > </mapper >
2、在接口中提供findById方法
1 2 3 4 5 6 public Emp findById (Integer id) ;
注意:方法的名字要和映射的sql标签的id值保持一致
方法的返回值类型和resultType的类型要一致
1 2 3 4 <select id ="findById" resultType ="com.tedu.pojo.Emp" > select * from emp where id=#{id} </select >
3、提供实现类,测试Emp接口中的根据id查询员工的方法
(1)创建com.tedu.test.TestMybatisInf类, 并提供testFindById方法
1 2 3 4 public class TestMybatisInf { @Test public void testFindById () throws Exception {} }
4、实现testFindById方法并测试
1 2 3 4 5 6 7 8 9 10 @Test public void testFindById () throws Exception { ...... EmpMapper map = session.getMapper(EmpMapper.class ) ; Emp e = map.findById(2 ); System.out.println(e); }
5、在接口中提供findAll方法
1 2 3 4 5 public List<Emp> findAll () ;
注意:方法的名字要和映射的sql标签的id值保持一致
方法的返回值类型和resultType的类型要一致, 例如:
1 2 3 4 <select id ="findAll" resultType ="com.tedu.pojo.Emp" > select * from emp </select >
6、提供实现类,测试Emp接口中的查询所有员工的方法
(1)创建com.tedu.test.TestMybatisInf类, 并提供testFindAll方法
1 2 3 4 5 public class TestMybatisInf { ... @Test public void testFindAll () throws Exception {} }
实现testFindAll方法并测试
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void testFindAll () throws Exception { ... EmpMapper map = session.getMapper(EmpMapper.class ) ; List<Emp> list = map.findAll(); for (Emp e : list) { System.out.println(e); } }
几个可以优化的地方 加入log4j日志框架 在项目中加入log4j的配置文件,用于打印日志信息,便于开发调试。
在src(或相似的目录)下创建log4j.properties如下:
1 2 3 4 5 6 log4j.rootLogger =DEBUG, stdout log4j.appender.stdout =org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout =org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern =%5p [%t] - %m%n
mybatis默认使用log4j作为输出日志信息。
只要将该文件放在指定的位置,log4j工具会自动到指定位置加载上述文件,读取文件中的配置信息并使用!
SQL语句中的特殊符号 示例:添加一个查询功能:查询薪资小于3500的所有员工。
1、编辑EmpMapper.xml文件, 添加查询对应的sql.
1 2 3 4 5 6 7 8 9 10 11 <select id ="findBySal" resultType ="com.tedu.pojo.Emp" > select * from emp where 2=2 <if test ="minSal != null" > and salary >= #{minSal} </if > <if test ="maxSal != null" > and salary <= #{maxSal } </if> </select >
2、但在书写完后,xml文件提示有错误:
image-20200407172154514
原来,小于号(<)在xml文件中是特殊字符,被xml文件当成了标签的开始符号。
3、解决方法:可以使用 <
代替 <
,例如:
1 2 3 4 5 6 7 8 9 10 <select id ="findBySal" resultType ="com.tedu.pojo.Emp" > select * from emp where 2=2 <if test ="minSal != null" > and salary >= #{minSal} </if > <if test ="maxSal != null" > and salary < = #{maxSal} </if > </select >
或者是将特殊符号包含在CDATA区( )中,这是因为放在CDATA区中的内容,只会被xml解析器当作普通文本来处理。而不是被当成标签的一部分处理。
1 2 3 4 5 6 7 8 9 10 11 <select id ="findBySal" resultType ="com.tedu.pojo.Emp" > select * from emp where 2=2 <if test ="minSal != null" > and salary >= #{minSal} </if > <if test ="maxSal != null" > and salary <![CDATA[ <= ]]> #{maxSal} </if > </select >
jdbc.properties文件 在开发中,通常我们会将连接数据库的配置信息单独放在一个properties文件中(方便管理和维护), 然后在MyBatis的mapper文件中引入properties文件的配置信息即可!
1、在src目录下创建一个名称为jdbc.properties的文件
c689eb39f8139c834ce014974d446229
2、jdbc.properties文件内容如下:
1 2 3 4 jdbc.driver =com.mysql.jdbc.Driver jdbc.url =jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8 jdbc.username =root jdbc.password =root
3、在mybatis-config.xml文件中引入jdbc.properties文件
7f967dea070cc2df6038dc0a11fcfc7e
1、其中 <properties resource="jdbc.properties"/>
标签用于引入jdbc.properties文件,默认到classpath即类目录下寻找指定的文件;
2、properties标签上value属性中配置的 $:
${jdbc.driver}
:其实就是jdbc.properties文件中的 jdbc.driver的值,即:
${jdbc.url}
:其实就是jdbc.properties文件中的 jdbc.url的值,即:
1 jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf-8
${jdbc.username}
:其实就是jdbc.properties文件中的 jdbc.username的值,即:
${jdbc.password}
:其实就是jdbc.properties文件中的 jdbc.password的值,即:
扩展内容 Jdbc回顾 通过JDBC查询Emp表中的所有记录,并封装到一个List集合中返回
1、创建TestJdbc类,完成查询所有员工:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 package com.tedu.jdbc;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.ArrayList;import java.util.List;import com.tedu.pojo.Emp;public class TestJdbc { public static void main (String[] args) { List<Emp> empList = findAll(); for (Emp emp : empList){ System.out.println(emp); } } private static List<Emp> findAll () { Connection conn = null ; Statement stat = null ; ResultSet rs = null ; try { Class.forName("com.mysql.jdbc.Driver" ); conn = DriverManager.getConnection( "jdbc:mysql:///yonghedb" , "root" , "root" ); stat = conn.createStatement(); String sql = "select * from emp" ; rs = stat.executeQuery(sql); List<Emp> empList = new ArrayList(); while (rs.next()) { int id = rs.getInt("id" ); String name = rs.getString("name" ); String job = rs.getString("job" ); double salary = rs.getDouble("salary" ); Emp emp = new Emp(); emp.setId(id); emp.setName(name); emp.setJob(job); emp.setSalary(salary); empList.add(emp); } return empList; } catch (Exception e) { e.printStackTrace(); System.out.println("查询失败!" ); } finally { if (rs != null ){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }finally { rs = null ; } } if (stat != null ){ try { stat.close(); } catch (SQLException e) { e.printStackTrace(); }finally { stat = null ; } } if (conn != null ){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }finally { conn = null ; } } } return null ; } }
2、声明Emp实体类,用于封装员工信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package com.tedu.pojo;public class Emp { private Integer id; private String name; private String job; private Double salary; 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 String getJob () { return job; } public void setJob (String job) { this .job = job; } public Double getSalary () { return salary; } public void setSalary (Double salary) { this .salary = salary; } @Override public String toString () { return "Emp [id=" + id + ", name=" + name + ", job=" + job + ", salary=" + salary + "]" ; } }
mybatis-config文件没有提示的解决办法 如果在没有网络(外网)的情况下,编写mybatis-config.xml文件没有提示,可以按照下面的步骤进行配置:
(1)找到mybatis-3-config.dtd的文件的位置,例如:
065e6b731aa74d5650821fdc63cbd4b9
(2)复制下面的url地址:
1 http://mybatis.org/dtd/mybatis-3-config.dtd
(3)在eclipse菜单栏中: window –> Preferences –> 在搜索框中搜索 [ xml ] XML –> XML Catalog –> User Specified Entries –> Add…
eef68594c0d7b072e09702b3d6289831
(4)在弹出的窗口中:
364a97a96fcb74e6ca14d4a9c8b89e6b
Mapper文件没有提示的解决办法 如果在没有网络(外网)的情况下,编写XxxMapper.xml文件没有提示,可以按照下面的步骤进行配置:
(1)找到mybatis-3-mapper.dtd的文件的位置,例如:
50f2e9357bd4d42791f85098a75795c0
(2)复制上面的url地址,即:
1 http://mybatis.org/dtd/mybatis-3-mapper.dtd
(3)在eclipse菜单栏中: window –> Preferences –> 在搜索框中搜索 [ xml ] XML –> XML Catalog –> User Specified Entries –> Add…
eef68594c0d7b072e09702b3d6289831
(4)在弹出的窗口中:
e907b64d04d56389acba7c7e2f6bd74c
配置达内XML Schema代理服务器 1、打开Eclipse的配置首选项
](https://www.zhangpeng.fun/upload/2020/06/eb81455caf93624c289a4e60105b6aca-67e645a62bde49b28fcc2e35a2589c87.png)
eb81455caf93624c289a4e60105b6aca
2、找到 XML -> XML Catalog, 添加配置项目:
bf2d8978925006db94220c283a695f57
3、添加URI代理配置, 比如:配置Spring Schema
7e5343736b72ca605ac7e577025ccd9e
4、可以配置的代理有