一、Mybatis入门案例
--查询yonghedb.emp表中所有员工信息
1.先创建一个Maven Project,Group Id:com.tedu; Artifact Id:CGB-MYBATIS-01; Packging:jar
2.在pom.xml里添加如下代码,用来配置各种环境,之后会在Maven Dependencies里显示
<dependencies>
<!-- junit单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
<!-- 整合log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
</dependencies>
3.在src/main/java里新建一个class类,命名为MyBatisTest01
4.新建xml,命名为mybatis-config.xml
把unit08-mybatis中的mybatis-config[模板].xml里的内容粘贴在建好的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>
<!-- 配置文件不要求大家记住,但需要大家会修改 -->
<!-- 1.配置开发环境 default等于哪个环境的id值就使用哪个环境 -->
<environments default="develop">
<environment id="develop">
<!-- 指定事务管理方式,type="JDBC":将事务交给JDBC来管理,type="MANAGED":自己管理事务 -->
<transactionManager type="JDBC" />
<!-- dataSource(其实就是数据源,也就是连接池):指定连接数据库的基本信息
type:POOLED就是使用连连接池UNPOOLED就是不使用连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql:///yonghedb?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!-- 2.导入MAPPER文件(SQL语句) resource指向MAPPER文件在类目录中的位置 -->
<mappers>
<mapper resource="EmpMapper.xml" />
</mappers>
</configuration>
5.新建xml,命名为EmpMapper.xml
把unit08-mybatis中的EmpMapper[模板].xml里的内容分别粘贴在建好的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="EmpMapper">
<!-- select insert update delete -->
<!-- 练习1:查询emp表中的所有员工信息 -->
<select id="findAll01" resultType="com.tedu.pojo.Emp">
select * from emp
</select>
</mapper>
6.新建一个类,命名为Emp,建在com.tedu.opjo包下,在里面添加如下代码
package com.tedu.pojo;
public class Emp {
private Integer id;
private String name;
private String job;
private Double salary;
// 提供Getting/Setting方法
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;
}
// 提供toString方法
@Override
public String toString() {
return "Emp [id=" + id + ", name=" + name + ", job=" + job + ", salary=" + salary + "]";
}
7.新建一个类,命名为MyBatisTest01,在里面添加如下代码:
public class MyBatisTest01 {
/* 练习01:查询yonghedb.emp表中所有员工信息 */
@Test
public void testFindAll01() throws Exception {
// 1.读取mybatis的核心配置文件(mybatis-config.xml)
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 2.获取SqlSessionFactory工厂对象
SqlSessionFactory fac = new SqlSessionFactoryBuilder().build(in);
// 3.获取SqlSession对象(true:自动提交事务,false[默认]:手动提交事务)
SqlSession session = fac.openSession(true);
// 4.执行SQL语句(EmpMapper.xml),返回处理后的结果,namespace+id--sql语句的定位标识
List<Emp> list = session.selectList("EmpMapper.findAll01");
// 5.输出结果到控制台
for (Emp emp : list) {
System.out.println(emp);
}
8.新建一个类,用来添加数据
二、Mybatis入门案例,跟上面对应
--新增员工信息:赵云 保安 6000
1.在EmpMapper.xml下添加如下代码
<!-- 练习2:新增员工信息:赵云 保安 6000 -->
<insert id="insert02">
insert into emp value(null,'赵云','保安',6000)
</insert>
复制一份MyBatisTest01,名字改为MyBatisTest02,在里面把前三行代码放在before里,做如下修改:
public class MyBatisTest02 {
private SqlSession session = null;
@Before /* 标记的方法会在@Test注标记的方法之前执行 */
public void testBefore() throws IOException {
// 1.读取mybatis的核心配置文件(mybatis-config.xml)
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 2.获取SqlSessionFactory工厂对象
SqlSessionFactory fac = new SqlSessionFactoryBuilder().build(in);
// 3.获取SqlSession对象(true:自动提交事务,false[默认]:手动提交事务)
session = fac.openSession(true);
}
/* 练习2:新增员工信息:赵云 保安 6000 */
@Test
public void testInsert02() throws Exception {
int rows = session.insert("EmpMapper.insert02");
System.out.println("Affected rows:" + rows);
// session.commit;上面加了session = fac.openSession(true);就不用每次都自己手动提交了
}
2.修改和删除跟添加的代码一模一样,同等原理
只需要在EmpMapper.xml添加一个update方法,修改insert02改为update03即为修改
练习3:修改员工信息:赵云 保镖 20000
@Test
public void testUpdate03() throws Exception {
int rows = session.update("EmpMapper.update03");
System.out.println("Affected rows:" + rows);
// session.commit;上面加了session = fac.openSession(true);就不用每次都自己手动提交了
}
3.只需要在EmpMapper.xml添加一个delete方法,修改insert02改为delete04即为删除
练习4:删除赵云
@Test
public void testDelete04() throws Exception {
int rows = session.delete("EmpMapper.delete04");
System.out.println("Affected rows:" + rows);
// session.commit;上面加了session = fac.openSession(true);就不用每次都自己手动提交了
}
三、Mybatis中的占位符
1.概念
自己:如果#占位符只有一个,括号里的名称可以随便写,但是不能空着,如果#占位符有多个,名称一定要和map中的key一致
老师:如果在SQL语句中只有一个#{}占位符,{}中名称没有要求,但不能是空的;
如果在SQL语句中的#{}占位符,不止一个,参数值需要通过Map或者P0J0对象进行封装;
如果通过Map集合来封装SQL参数值,#{}占位符中的名称要和Map中的key保持一致!
因为在mybatis底层是通过#{}占位符中的名称,作为key到map中获取对应的value;如果通过P0J0对象来封装SQL参数值
#{}占位符中的名要在PO10对象中有对应的getXx方法,
例如∶#{job}占位符中的名称为job,那么就意味着,在Emp中必然有getJob()方法或者有job变量
如果两者都有,会优先通过getXXx方法来获取PO30对象中存储的属性值
pojo:简单java对象,专指用于封装数据的对象
2.查询emp表中指定id的员工信息
@Test
public void testFindById05() throws IOException{
int id=5;
Emp emp=session.selectOne("EmpMapper.findById05",id);
System.out.println(emp);
}
在EmpMapper.xml添加如下代码:
<!-- 练习5:查询emp表中指定id的员工信息 -->
<select id="findById05" resultType="com.tedu.pojo.Emp">
<!-- #{},花括号里面的值时占位符的名称,如果#占位符只有一个,括号里的名称可以随便写,但是不能空着 -->
select * from emp where id=#{id};
</select>
3.新增员工信息:张飞 Java开发工程师15000
@Test
public void testInsert06() throws IOException {
// 将要传输的参数封装到map集合中
Map map = new HashMap();
map.put("name", "张飞");
map.put("job", "Java开发工程师");
map.put("salary", 15000);
// 也可以将要传输的参数封装到Emp对象中
int rows = session.insert("EmpMapper.insert06", map);
System.out.println("Affected rows:" + rows);
}
在EmpMapper.xml添加如下代码:
<!-- 练习6:新增员工信息:张飞 Java开发工程师15000 名称一定要和map中的key一致-->
<insert id="insert06">
insert into emp value( null,#{name},#{job},#{salary})
</insert>
4.修改员工信息:于影 CEO 100000000000000
@Test
public void testUpdate07() throws IOException {
// 可以将SQL参数值封装到POJO对象中,再将POJO对象传递给SQL
Emp emp = new Emp();
emp.setName("于影");
emp.setJob("CEO");
emp.setSalary(100000000000000D);
int rows = session.update("EmpMapper.update07",emp);
System.out.println("Affected rows:" + rows);
}
在EmpMapper.xml添加如下代码:
<!-- 练习7:修改员工信息:于影 CEO 100000000000000 -->
<update id="update07">
update emp set job=#{job},salary=#{salary} where name=#{name}
</update>
5.删除emp表中指定id的员工信息
四、几个可以优化的地方
1.加入log4j日志框架(新建一个log4j.properties文件,在讲义中可以优化的地方下方粘贴代码在log4j.properties文件里)
导入log4j的jar包,在源码根目录下提供一个 log4j.properties 文件,并提供配置信息,代码如下:
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
2、${}占位符
#{}占位符∶相当于JDBC中的问号(?)占位符,它是为SQL语句中的参数值进行占位,例如下方代码:
insert into emp values(null,#{name},#{job},#(salary));
update emp set job=#(job},salary=#(salary} where name=#{name}
delete from emp where name=#{name}
delete from emp where id=#{id)
select* from emp where name=#{name} and job=#{job}
${}占位符:是为SQL语句中的某一个SQL片段进行占位,将参数传递过来时,是直接将参数拼接在${}占位符所在的位置
因为是直接拼接,所以可能会引发SQL注入攻击,因此不推荐大量使用
如果SQL语句中只有一个#{}占位符,参数可以不用封装,直接传递即可!
但如果SQL语句中哪怕只有一个${}占位符,参数也必须得先封装到Map或者P0J0对象中,再把Map或者POJ0对象传递过去
3.动态指定要显示的列
练习8:动态指定要显示的列
@Test
public void testFindAll08() throws Exception{
String colName = "*";
Map map = new HashMap();
map.put("colName", colName);
List<Emp> list = session.selectList("EmpMapper.findAll08");
for (Emp emp : list) {
System.out.println(emp);
}
}
在EmpMapper.xml文件里添加如下代码
<!-- 练习8:动态指定要显示的列 -->
<select id="findAll08" resultType="com.tedu.pojo.Emp">
select ${colName} from emp
</select>
4.根据name模糊查询emp表,查询姓刘的,用${}占位符
@Test
public void testFindAll09() throws Exception {
Map map = new HashMap();
map.put("name","刘");
List<Emp> list = session.selectList("EmpMapper.findAll09", map);
for (Emp emp : list) {
System.out.println(emp);
}
}
在EmpMapper.xml文件里添加如下代码
<!-- 练习9:根据name模糊查询emp表,查询姓刘的,用${}占位符 -->
<select id="findAll09" resultType="com.tedu.pojo.Emp">
select * from emp where name like '%${name}%'
</select>
5.根据name模糊查询emp表,查询姓刘的,用#{}占位符
@Test
public void testFindAll09() throws Exception {
Map map = new HashMap();
map.put("name","%刘%");
List<Emp> list = session.selectList("EmpMapper.findAll09", map);
for (Emp emp : list) {
System.out.println(emp);
}
}
在EmpMapper.xml文件里添加如下代码
<!-- 练习10:根据name模糊查询emp表,查询姓刘的,用${}占位符 -->
<select id="findAll10" resultType="com.tedu.pojo.Emp">
select * from emp where name like #{name}
</select>
PreparedStatement对象:
1)先将SQL骨架发送给数据库服务器进行编译并确定下来(骨架一旦确定,就无法更改)
2)再将SQL中的参数传递给服务器(此时如果参数中再包含关键字或者SQL特殊字符串,也不能影响骨架,只会被当成普通的文本来处理!)
五、动态SQL标签
1.根据薪资查询员工信息
>的转义是> <号的转义是<
练习11:根据薪资查询员工信息
@Test
public void testFindBySalary11() {
Map map = new HashMap();
map.put("minSal", 3000);
map.put("maxSal", 4000);
List<Emp> list = session.selectList("EmpMapper.findBySalary11", map);
for (Emp emp : list) {
System.out.println(emp);
}
}
在EmpMapper.xml文件里添加如下代码:
<!-- 练习11:根据薪资查询员工信息 >的转义是> <号的转义是< 或可以把特殊符号放在<![CDATA[ ]]>里面 -->
<select id="findBySalary11" resultType="com.tedu.pojo.Emp">
select * from emp
<!-- 1=1加在where后面什么作用都没有,因为跟表没有任何关系,和不加where一个效果 -->
where 1=1
<if test="minSal != null">
and salary >= #{minSal}
</if>
<if test="maxSal != null">
and salary <= #{maxSal}
</if>
</select>
2.根据薪资查询员工信息(where标签)
跟练习11一样的结果,就是把EmpMapper文件中的select标签内容中的where1=1换成了where标签
id改为findBySalary12,代码如下:
练习12:根据薪资查询员工信息(where标签)
<select id="findBySalary12" resultType="com.tedu.pojo.Emp">
select * from emp
<where>
<if test="minSal != null">
and salary >= #{minSal}
</if>
<if test="maxSal != null">
and salary <= #{maxSal}
</if>
</where>
</select>
3.根据员工的id批量删除员工信息(13省略,省略的是练习8:删除emp表中指定id的员工信息)
/* 练习14:根据员工的id批量删除员工信息 */
@Test
public void testFindBySalary14() {
Integer[] ids = { 4 };
int rows = session.delete("EmpMapper.deleteByIds14", ids);
System.out.println("Affected rows:" + rows);
}
在EmpMapper.xml文件里添加如下代码
<delete id="deleteByIds14">
delete from emp where id in
<foreach collection="array" open="(" item="id" separator=","
close=")">#{id}</foreach>
</delete>
4.foreach标签:
(1)如果传的参数仅仅是一个数组或者List集合,collection指定的值则为array或list
如果传的参数有多个,用map集合进行封装,collection指定的值则为数组/集合在map中的key
(2)open:指定所生成字符串的起始符号
(3)close:指定所生成字符串的结束符号
(4)item:指定占位符中的名称
(5)separator:指定遍历的元素之间的间隔符
5.根据员工的id批量更新员工薪资
/* 练习15: 根据员工的id批量更新员工信,将id为 6,14,15,19的员工的薪资在原有基础上增加1000 */
@Test
public void testUpdateByIds() {
Integer[] ids = { 6, 14, 15, 19 };
Map map = new HashMap();
map.put("count", 10000);
map.put("idsArr", ids);
int rows = session.update("EmpMapper.updateByIds15", map);
System.out.println("Affected rows:" + rows);
}
在EmpMapper.xml文件里添加如下代码
<!-- 练习15:将id为 6,14,15,19的员工的薪资在原有基础上增加1000 -->
<update id="updateByIds15">
update emp set salary = salary+1000 where id in (6,14,15,19)
update emp set salary = salary + #{count} where id in
<foreach collection="idsArr" open="(" item = "sal" separator="," close=")">
#{sal}
</foreach>
</update>
六、Mapper接口开发
mapper接口开发需满足一下四个原则
1.写一个接口,要求接口的全类名(包名+接口名)要等于mapper文件的namespace值
namespace = 接口的全类名
2.mapper文件中要执行的SQL,在接口中得到对应的接口方法,而且SQL标签的ID值要等于方法名
SQL语句的ID值 = 方法名
3.如果是查询SQL,resultType属性中指定的类型,要和接口方法的返回值类型保持一致
(如果接口方法返回的是List集合,resultType属性只需要指定集合中的泛型)
4.SQL标签的参数类型(可以省略)要和接口方法的参数类型保持一致
七、Mapper接口开发的练习
1.把CGB-MYBATIS-01复制一份,改为CGB-MYBATIS-01,复制com.tedu的MyBatisTest02复制一份,改为MyBatisTest03, 删除01,02,MyBatisTest03类里面只留before和private SqlSession session = null;
2.新建一个接口,命名为EmpMapper,包名命名为com.tedu.dao,建好之后右键EmpMapper选择copy Qualified name(全类名)
3.打开EmpMapper.xml文件找到mapper的namespace,把接口全类名粘贴进去,必须和全类名一致
4.在EmpMapper接口里添加一个方法,方法名字要和id值一致,代码如下
public interface EmpMapper {
// 查询所有员工的信息
public List<Emp> findAll01();
}
5.在MyBatisTest03类中添加一个方法,代码如下
/* Mapper接口开发01:查询emp表所有信息 */
@Test
public void testFindAll01() {
/* (1)获取EmpMapper接口的实现类实例
* 框架底层可以根据GetMappper方法接收的EmpMapper接口的字节码对象,提供接口的实现类
* 并根据接口的实现类,创建实现类的实例,同时也可以获取接口的全类名(=namespace)
*/
括号里传接口的字节码对象,也就是class对象,接口名.class
把字节码对象传给GetMappper方法,并实现接口
EmpMapper mapper = session.getMapper(EmpMapper.class);
/* (2)调用findAll01方法
*
*
*/
List<Emp> list = mapper.findAll01();
for (Emp emp : list) {
System.out.println(emp);
}
}
八、MyBatis注解开发
xml修改方便,编写起来很麻烦,对语法要求很严格,注解开发修改不方便,编写起来方便
1.在接口上方写一个select注解代替查询
@Select("select * from emp")
2.在接口上方写一个insert注解代替添加
@insert("insert into emp value( null,#{name},#{job},#{salary})")
3.在接口上方写一个update注解代替修改
@Update("update emp set name=#{name},job=#{job},salary=#{salary} where id=#{id}")
4.在接口上方写一delete个注解代替删除
@Delete("delete from emp where id=#{id}")
SQL语句加判断很麻烦,可读性差
@Select("<script>select * from emp where 1=1 <if test=\"minSal!=null\">
and price > minSal </if><script>")
九、内容补充
1.POJO(Plain Old Java Object/Plain Ordinary Java Object)
简单Java对象:是指专门用于封装数据的数据的对象
2.Emp中的属性为什么不能是基本类型
public class Emp{
private Integer id;
private String name;
private String job;
private Double salary;//默认值为null;
private double score; //默认值为0.0;
}