一、概述
三层架构
三层
1、界面层:和用户打交道,接受用户的请求参数,显示处理结果。(jsp、html、servlet)
2、业务逻辑层:接受页面层传递的数据,计算逻辑,调用数据库,获取数据。
3、数据访问层:就是访问数据库,对数据库中的数据增删改查。
三层架构对应的包
1、界面层:controller包(servlet)
2、业务逻辑层:service包(XXXServicelei)
3、数据访问层:dao包(XXXDao类)
三层中类的交互
用户使用界面层---->业务逻辑层–>数据访问层(持久层)–>数据库
三层对应的处理框架
界面层:servlet----springmvc(框架)
业务逻辑层:service类----spring(框架)
数据访问层:dao类----MyBatis(框架)
框架
框架是一个舞台,一个模板。
1、框架中定义了一些功能。这些功能是可用的。
2、可以加入项目中自己的功能,这些功能可以利用框架中写好的功能。
框架是一个软件,半成品软件,定义好了一些功能,需要加入自己所需的功能就完整了。
基础功能是可重复使用的,可升级的。
框架特点
1、框架不是全能的,不能做所有事情
2、框架是针对某一领域有效。
3、框架是一个半成品软件。
JDBC缺陷
大量的代码重复,核心就只是sql语句,效率低。
需要关注Connection,Statement,ResultSet对象的创建和关闭。
对查询结果ResultSet需要自己封装成List
业务代码和数据库操作混在一起
MyBatis框架概述
减轻使用JDBC的复杂性,不用编写重复的创建Connection,Statement;不用编写关闭资源代码。直接使用java对象,表示结果数据。
可以完成:
1、注册数据库驱动。
2、创建JDBC必须使用的Connection,Statement,ResultSet对象。
3、从xml中获取sql,并执行sql语句,把ResultSet结果转换成java对象。
4、
主要功能
1、sql mapper
sql映射。可以把表中的一行数据映射为一个java对象。一行数据可以看作一个java数据。操作这个对象相当于操作表中的数据。
2、Data Access Objects
DAOs 数据访问。对数据库执行增删改查。
MyBatis提供功能
1、创建Connection,Statement,ResultSet的能力,不需要开发人员创建。
2、提供了执行sql语句的能力
3、提供了循环sql,把sql结果转为java对象,List集合的能力
4、提供了资源关闭的能力。
达到开发人员只需提供sql语句,MyBatis处理sql,开发人员得到List集合或Java对象。
二、入门
准备工作
配置日志功能
mybatis.xml文件中加入日志配置:可以在控制台输出执行的sql语句和参数
settings:控制mybatis全局行为的。
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
基本步骤
本地文件实例:D:\JAVACODE\MyBatis\ch01
1、加入maven依赖
pom.xml 中加入mybatis依赖
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
pom.xml 中加入mysql驱动依赖
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
2、创建Dao接口
定义了操作数据的方法
创建dao包,在此包下创建XXXDao接口
package com.daihan.dao;
import com.daihan.domain.Student;
import java.util.List;
//接口,操作Student表
public interface StudentDao {
//查询student表所有数据
public List<Student> selectStudent();
//插入方法
//参数student表示插入到数据库的数据
//返回值表示执行insert之后,影响数据库的行数
public int insertStudent(Student student);
}
3、创建mapper文件
也叫做sql映射文件:写sql语句的,和接口中方法对应的sql语句。
注:mapper文件与Dao接口在想同包下(dao包),且文件名相同,mapper文件扩展名为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.daihan.dao.StudentDao">
<!--
select:表示查询操作
id:要执行的sql语句的唯一标识,mybatis会使用这个id值来找到要执行的sql语句
可以自定义,但要求使用接口中的方法名
resultType:表示结果类型的,是sql语句执行结束之后得到的ResultSet得到Java对象的类型
值写的是类型的全限定名称
-->
<select id="selectStudent" resultType="com.daihan.domain.Student">
select id,name,email,age from student order by id
</select>
<!--例2 插入操作-->
<insert id="insertStudent">
<!--#{属性名} 表示占位符,到时候去实例对象中取具体值-->
insert into student values(#{id},#{name},#{email},#{age})
</insert>
</mapper>
<!--
sql映射文件(sql mapper):是写sql语句的,mybatis会执行这些sql
1、指定约束文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
mybatis-3-mapper.dtd是约束文件的名称,扩展名是dtd
2、约束文件的作用:
限制、检查在当前文件中出现的标签,属性必须符合mybatis的要求。
3、mapper 是当前文件的根标签,必须的。
namespace:叫做命名空间,唯一值,可以是自定义的字符串
要求使用dao接口的全限定名称。
4、在当前文件中,可以使用特定的标签,表示数据库的操作
<select>:表示执行查询
<update>:表示执行更新
<delete>:表示执行删除
<insert>:表示执行插入
-->
4、创建mybatis的主配置文件
作用:
1、连接数据库
2、指定mapper文件的位置
位置:
main/resources目录下的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>
<!--
环境配置:数据库的连接信息
default:必须和某个environment的id值一样。
告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
-->
<environments default="mydev">
<!-- environment:一个数据库信息的配置,环境
id是个唯一值,自定义的,表示环境名称,用于说明当前使用的库。
通过改动对应值,切换数据库。
-->
<!--开发使用的库-->
<environment id="mydev">
<!--
transactionManager:mybatis的事务类型
type:JDBC(表示使用JDBC中的Connection对象的commit,rolllback)
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示数据源,连接数据库的
type:表示数据源类型,POOLED表示使用连接池
-->
<dataSource type="POOLED">
<!--
driver,url,username,password是固定的,不能随意改
-->
<!--数据库的驱动类名-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--连接数据库的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>
<!--访问数据库的用户名-->
<property name="username" value="root"/>
<!--访问数据库的密码-->
<property name="password" value="a123b456"/>
</dataSource>
</environment>
<!--表示线上的数据库,是项目真实使用的库-->
<environment id="online">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="a123b456"/>
</dataSource>
</environment>
</environments>
<!--sql mapper(sql映射文件)的位置-->
<mappers>
<!--
一个mapper标签指定一个文件的位置
从类路径开始的路径信息。target/classes(类路径)
-->
<mapper resource="com/daihan/dao/StudentDao.xml"/>
</mappers>
</configuration>
<!--
这是mybatis的主配置文件:主要定义了数据库的配置信息,sql映射文件的位置
1、约束文件
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
mybatis-3-config.dtd:约束文件的名称
2、<configuration>根标签
-->
5、使用mybatis对象
使用mybatis对象SqlSession,通过它的方法执行sql语句
例1,执行查询
public class MyApp {
public static void main(String[] args) throws IOException {
//访问MyBatis读取student数据
//1、定义MyBatis主配置文件的名称,从类路径根开始(target/classes)
String config = "mybatis.xml";
//2、读取这个文件
InputStream in = Resources.getResourceAsStream(config);
//3、创建sqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4、创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
//5、【重要】获取SqlSession对象,从SqlSessionFactory中获取
SqlSession sqlSession = factory.openSession();
//6、【重要】指定要执行的sql语句的标识.使用sql映射文件中的namespace+"."+标签的id值
String sqlid = "com.daihan.dao.StudentDao" + "." + "selectStudent";
//7、执行sql语句,通过sqlid找到语句
List<Student> studentList = sqlSession.selectList(sqlid);
//8、输出结果
studentList.forEach(student -> System.out.println(student));
//9、关闭SqlSession对象
sqlSession.close();
}
}
例2,执行插入
public void testInsert() throws IOException {
//访问MyBatis读取student数据
//1、定义MyBatis主配置文件的名称,从类路径根开始(target/classes)
String config = "mybatis.xml";
//2、读取这个文件
InputStream in = Resources.getResourceAsStream(config);
//3、创建sqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4、创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
//5、【重要】获取SqlSession对象,从SqlSessionFactory中获取
SqlSession sqlSession = factory.openSession();
//6、【重要】指定要执行的sql语句的标识.使用sql映射文件中的namespace+"."+标签的id值
String sqlid = "com.daihan.dao.StudentDao" + "." + "insertStudent";
//7、执行sql语句,通过sqlid找到语句
Student student1 = new Student();
student1.setId(1003);
student1.setName("张飞");
student1.setEmail("zhangfei@163.com");
student1.setAge(20);
int nums = sqlSession.insert(sqlid,student1);
//mybatis默认是不会提交事务,在insert,update,delete后需要手动提交
sqlSession.commit();
//8、输出结果
System.out.println("执行insert的结果:"+nums);
//9、关闭SqlSession对象
sqlSession.close();
}
使用工具类(进阶)
因为核心是获取SqlSession
com.daihan下创建新的package:MyBatisUtil
package com.daihan.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisUtil {
private static SqlSessionFactory factory=null ;
static {
String config="mybatis.xml";//需要和项目名对应
try {
InputStream in=Resources.getResourceAsStream(config);
//创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
factory=new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession的方法
public static SqlSession getSqlSession(){
SqlSession sqlSession=null;
if (factory!=null){
sqlSession=factory.openSession();//非自动提交事务
}
return sqlSession;
}
}
主函数可以改为:
package com.daihan;
import com.daihan.domain.Student;
import com.daihan.utils.MyBatisUtil;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyApp2 {
public static void main(String[] args) throws IOException {
//【重要】获取SqlSession对象,从SqlSessionFactory中获取
SqlSession sqlSession = MyBatisUtil.getSqlSession();
//【重要】指定要执行的sql语句的标识.使用sql映射文件中的namespace+"."+标签的id值
String sqlid = "com.daihan.dao.StudentDao" + "." + "selectStudent";
//执行sql语句,通过sqlid找到语句
List<Student> studentList = sqlSession.selectList(sqlid);
//输出结果
studentList.forEach(student -> System.out.println(student));
//关闭SqlSession对象
sqlSession.close();
}
}
主要的类介绍
1、Resources
mybatis中的一个类,负责读取主配置文件
InputStream in = Resources.getResourceAsStream("mybatis.xml");
2、SqlSessionFactoryBuilder
用来创建SqlSessionFactory对象
一、创建SqlSessionFactoryBuilderSqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
二、使用builder创建SqlSessionFactory对象SqlSessionFactory factory = builder.build(in);
3、SqlSessionFactory(重要)
重量级对象,程序创建这个对象耗时长,使用资源多,在整个项目中有一个就够了。
SqlSessionFactory是一个接口,接口默认实现类:DefaultSqlSessionFactory,
SqlSessionFactory作用:获取SqlSession对象。SqlSession sqlSession = factory.openSession();
openSession()方法说明:
1、openSession()无参数,获取非自动提交事务的SqlSession对象
2、openSession(boolean):参数true时,是获取自动提交事务的SqlSession;参数false时,是获取非自动提交事务的SqlSession对象。
SqlSession(重要)
SqlSession是接口,定义了操作数据库的方法,例如:selectONe(),selectList(),insert(),update(),delete(),commit(),rollback()。
SqlSession接口实现类DefaultSqlSession,
使用要求:SqlSession对象不是线程安全的,需要在方法内部使用,在执行sql语句之前要使用openSession()获取SqlSession对象,在执行sql语句之后,需要关闭它,执行SqlSession.close();这样保证线程安全。
MyBatis使用传统Dao开发
本地文件位置:D:\JAVACODE\MyBatis\ch02-nybatis-dao
规律:
资源配置文件
main下新建resources目录
创建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>
<settings>
<!--设置mybatis打印日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="mydev">
<environment id="mydev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="a123b456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/daihan/dao/StudentDao.xml"/>
</mappers>
</configuration>
创建dao包
1、定义接口
package com.daihan.dao;
import com.daihan.domain.Student;
import java.util.List;
public interface StudentDao {
List<Student> selectStudents();
int insertStudent(Student student);
}
2、dao下子包定义接口实现类
package com.daihan.dao.impl;
import com.daihan.domain.Student;
import com.daihan.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class StudentDaoImpl implements com.daihan.dao.StudentDao {
@Override
public List<Student> selectStudents() {
//1、获取SqlSession对象
SqlSession sqlSession= MyBatisUtil.getSqlSession();
String sqlId="com.daihan.dao.StudentDao"+'.'+"selectStudents";
//2、执行sql语句,使用SqlSession类的方法
List<Student> students=sqlSession.selectList(sqlId);
//3、关闭
sqlSession.close();
return students;
}
@Override
public int insertStudent(Student student) {
//1、获取SqlSession对象
SqlSession sqlSession= MyBatisUtil.getSqlSession();
String sqlId="com.daihan.dao.StudentDao"+'.'+"insertStudent";
//2、执行sql语句,使用SqlSession类的方法
int nums=sqlSession.insert(sqlId,student);
//提交事务
sqlSession.commit();
//3、关闭
sqlSession.close();
return nums;
}
}
3、dao接口同名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.daihan.dao.StudentDao">
<select id="selectStudents" resultType="com.daihan.domain.Student">
select id,name,email,age from student order by id
</select>
<insert id="insertStudent" >
insert into student values (#{id},#{name},#{email},#{age})
</insert>
</mapper>
创建domain包下实体类
package com.daihan.domain;
public class Student {
//定义属性,目前属性名和列名一致
private Integer id;
private String name;
private String email;
private Integer age;
public Student() {
}
public Student(Integer id, String name, String email, Integer age) {
this.id = id;
this.name = name;
this.email = email;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
创建工具包util
package com.daihan.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisUtil {
private static SqlSessionFactory factory=null ;
static {
String config="mybatis.xml";//需要和项目名对应
try {
InputStream in=Resources.getResourceAsStream(config);
//创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
factory=new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession的方法
public static SqlSession getSqlSession(){
SqlSession sqlSession=null;
if (factory!=null){
sqlSession=factory.openSession();//非自动提交事务
}
return sqlSession;
}
}
主程序
在test/java/com/daihan/新建主程序
package com.daihan;
import com.daihan.dao.StudentDao;
import com.daihan.dao.impl.StudentDaoImpl;
import com.daihan.domain.Student;
import org.junit.Test;
import java.util.List;
public class TestMyBatis {
@Test
public void testSelectStudent(){
StudentDao dao = new StudentDaoImpl();
List<Student> studentList=dao.selectStudents();
for(Student stu:studentList){
System.out.println(stu);
}
}
@Test
public void testInsertStudent(){
StudentDao dao = new StudentDaoImpl();
int nums= dao.insertStudent(new Student(1004,"王五","wangwu@163.com",20));
System.out.println("添加对象:"+nums);
}
}
三、Dao代理(核心)
1、MyBatis动态代理机制(重点)
本地文件位置:D:\JAVACODE\MyBatis\ch03-proxy-dao
重点是:使用sqlSession.getMapper(dao接口.class) ,获取这个dao接口的对象
1、dao对象,类型是StudentDao,全限定名称:com.daihan.dao.StudentDao
全限定名称和namespace一致
2、方法名称,selectStudents,这个方法就是mapper文件的id值
通过dao方法中的返回值也可以确定MyBatis要调用的SqlSession方法
如果返回值是List,调用的是SqlSession.selectList()方法
如果返回值是int,看mapper中的标签是<insert>或是<update>...
mybatis动态代理:mybatis根基dao方法调用,获取执行sql语句的信息。
根据dao接口创建dao接口的实现类,并创建个类对象,完成SqlSession调用,访问数据库
使用动态代理机制,不再需要实现dao包下XXXDao接口中的方法。
主程序
package com.daihan;
import com.daihan.dao.StudentDao;
import com.daihan.domain.Student;
import com.daihan.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class TestMyBatis {
@Test
public void testSelectStudent(){
/*
使用mybatis的动态代理机制,使用SqlSession.getMapper(dao接口)
getMapper能获取dao接口对应的实现类对象
*/
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
//底层自动生成实现类
System.out.println("类"+dao.getClass().getName());
//调用dao方法,执行数据库的操作
List<Student> studentList = dao.selectStudents();
for(Student stu:studentList){
System.out.println(stu);
}
}
@Test
public void testInsertStudent(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
调用dao方法,执行数据库的操作
int nums= dao.insertStudent(new Student(1005,"关羽","guanyu@163.com",20));
sqlSession.commit();
System.out.println("添加对象:"+nums);
}
}
2、深入理解参数(重点)
从Java代码中把参数传到xml文件中。
1、parametType
写在mapper文件中的一个属性。表示dao接口中方法的参数的数据类型。
例如StudentDao接口
public Student selectStudentById(Integer id)
2、传入一个简单类型的参数:
在mapper文件获取简单类型的一个参数的值,使用#{任意字符串}
接口:public Student selectStudentById(Integer id);
mapper:select id,name,email,age from student where id=#{id}
3、传入多个参数(掌握前两个)
1)使用@Param(重要)
当Dao接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”),mapper文件使用#{自定义参数名}
例如:定义List<Studnet> selectStudent( @Param("personName") String name,Integer age)
mapper文件 select * from student where name=#{personName}
例如:
dao包下StudentDao接口中
package com.daihan.dao;
import com.daihan.domain.Student;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface StudentDao {
/*
传入一个简单类型的参数:
在mapper文件获取简单类型的一个参数的值,使用#{任意字符串}
*/
public Student selectStudentById(Integer id);
/*
多个参数:命名参数,在形参定义前面加入@Param("自定义参数名称")
*/
List<Student> selectMultiParam(@Param("myname")String name,
@Param("myage")Integer age);
}
dao包下StudentDao.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.daihan.dao.StudentDao">
<select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.daihan.domain.Student">
select id,name,email,age from student where id=#{id}
</select>
<!--多个参数,使用@Param命名-->
<select id="selectMultiParam" resultType="com.daihan.domain.Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>
</mapper>
实体类和工具类同上,省略
测试主程序:
public class TestMyBatis {
@Test
public void testSelectMultiParam(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectMultiParam("关羽",20);
for(Student stu:students){
System.out.println("学生:"+stu);
}
}
}
2)使用对象传参(使用最多)
新建包vo,新建实体类:
(也可以不新增实体类,继续用已有的,例如Student类)
package com.daihan.vo;
public class QueryParam {
private String paramName;
private Integer paramAge;
public String getParamName() {
return paramName;
}
public Integer getParamAge() {
return paramAge;
}
public void setParamName(String paramName) {
this.paramName = paramName;
}
public void setParamAge(Integer paramAge) {
this.paramAge = paramAge;
}
}
dao包下StudentDao接口中新建方法:
/*
多个参数,使用java对象作为接口中方法的参数
*/
List<Student> selectMultiObject(QueryParam param);
dao包下StudentDao.xml中新增:
<!--
多个参数,使用java对象的属性值,作为参数实际值
使用对象语法:#{属性名,javaType=类型名称,jdbcType=数据库类型}
javaType:指java中的属性数据类型
jdbcType:在数据库中的数据类型
例如:#{paramName,javaType=java.lang.String,jdbcType=varchar}
简化:
#{属性名},javaType,jdbcType的值mybatis发射能获取。不用提供
-->
<!--<select id="selectMultiObject" resultType="com.daihan.domain.Student">
select id,name,email,age from student where
name=#{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
or age=#{paramAge,javaType=java.lang.Integer,jdbcType=INTEGER}
</select>-->
<select id="selectMultiObject" resultType="com.daihan.domain.Student">
select id,name,email,age from student where
name=#{paramName}
or age=#{paramAge}
</select>
测试程序增加测试方法:
@Test
public void testSelectMultiObject(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
QueryParam param = new QueryParam();
param.setParamAge(20);
param.setParamName("李四");
List<Student> students = dao.selectMultiObject(param);
for(Student stu:students){
System.out.println("学生:"+stu);
}
}
3)按位置传参(不建议)
从0开始,计算位置。
传的是简单类型的参数
语法:
接口方法中:参数列表(参数类型 参数名,…)
xml文件中:#{arg0}、#{arg1}...
4)Map传参 (不建议)
xml文件中#{key1},#{key2}…通过key传参
缺点:可读性差,map中key的值改动,xml文件#{key}也要改
#和$区别
#(首选)
告诉mybatis使用实际的参数值替代。并使用PrepareStatement对象执行sql语句,#{…}代替sql语句中的“?”。
$
告诉mybatis使用$
包含的字符串替换所在位置。使用Statement把sql语句和${}
的内容连接起来。主要用在替换表名,列名,不同列排序等操作。
区别
1、#
使用?在sql语句中做占位符,使用PrepareStatement对象执行sql语句,效率高。并且能防注入
2、$
不使用占位符,是字符串拼接方式,使用Statement执行sql语句,效率低。有注入风险。
3、$
可以替换表名或列名
3、封装MyBatis输出结果
MyBatis输出结果:MyBatis执行了sql语句,得到Java对象。
resultType和resultMap不能同时使用。
1)resultType
resultType:执行sql得到ResultSet转换的类型,使用类型的完全限定名或别名。注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。
处理方式:
1、mybatis执行sql语句,然后mybatis调用类的无参构造方法,创建对象。
2、mybatis把ResultSet指定列值付给同名属性。
2)定义别名
1、在mybatis主配置文件中定义,使用<typeAlias>定义别名
2、可以在resultType中使用别名
例如:
<typeAliases>
<!--
第一种方式
可以指定一个类型一个别名
type是要自定以别名的类的全限定名称
alias是自定义别名
-->
<typeAlias type="com.daihan.domain.Student1" alias="stu1"/>
<typeAlias type="com.daihan.domain.Student2" alias="stu2"/>
...
<!--
第二种方式
<package name>name是包名,这个包中所有类,类名就是别名(不区分大小写)
-->
<package name="com.daihan.domain"/>
<package name="com.daihan.vo"/>
...
</typeAliases>
3)查询返回Map(用的少)
dao包下接口XXXDao的方法:
Map<Object,Object> selectMapById(Integer id){};
dao包下XXXDao.xml文件
<!--
返回Map
1、属性名是Map的key,属性值是Map的value
2、返回Map的时候,最多返回一行记录
-->
<select id="selectMapById" resultType="java.util.Map">
select id,name,email,age from student where id=#{id}
</select>
test/java/com/daihan/Test主程序中新增方法
@Test
public void testSelectMapById(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
Map<Okbject,Object> map=dao.selectMapById(1001);
for(Student stu:students){
System.out.println("学生:"+stu);
}
}
4)resultMap 结果映射
指定列名(属性名)和java对象的属性对应关系。
resultMap和resultType不能同时使用,二选一。
1、自定义列值赋值给哪个属性(原本默认赋值给同名的属性)
2、当列名和属性名不一样时,一定要使用result
dao包下XXXDao接口中,增加方法
//使用resultMap定义映射关系
List<Student> selectAllStudents();
dao包下XXXDao.xml,增加
<!--
使用resultMap
1、先定义resultMap
2、在select标签,使用resultMap来引用1定义的resultMap
-->
<!--
id:自定义的名称,表示自定义的这个resultMap
type:java类型的全限定名称
-->
<resultMap id="studentMap" type="com.daihan.domain.Student">
<!--
定义列名和java属性的关系
column:列名
property:java属性名
主键列用id;非主键列使用result
-->
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="email" property="email"/>
<result column="age" property="age"/>
</resultMap>
<select id="selectAllStudents" resultMap="studentMap">
select id,name,email,age from student
</select>
测试主方法:略
列名属性名不同第二种解决方案
新增实体类MyStudent:略
dao包下XXXDao接口中,增加方法
//使用resultMap定义映射关系
List<MyStudent> selectDifferentColumnProperty();
dao包下XXXDao.xml,增加
<!--
resultType默认原则是:同名的列赋值给同名的属性,使用列别名(java对象属性名)
-->
<select id="selectDifferentColumnProperty" resultType="studentMap">
select id as stuId,name as stuName,email as stuEmail,age as stuAge from student
</select>
测试主方法:略
模糊Like
第一种方式(推荐)
在java代码中指定like内容
dao包下XXXDao接口中,增加方法
//第一种模糊查询,在java代码中指定like内容
List<Student> selectLikeOne(String name);
dao包下XXXDao.xml,增加
<!--第一种like,java代码中指定like内容-->
<select id="selectLikeOne" resultType="com.daihan.domain.Student">
select id,name,email,age from student where name like #{name}
</select>
测试主方法:
@Test
public void testSelectLikeOne(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
//准备like内容
String name="%李%";
List<Student> students = dao.selectLikeOne(name);
for(Student stu:students){
System.out.println("学生:"+stu);
}
}
第二种方式
在mapper文件中拼接like内容
dao包下XXXDao接口中,增加方法
//第二种模糊查询,在mapper中拼接 "%"+"李"+"%"
List<Student> selectLikeTwo(String name);
dao包下XXXDao.xml,增加
<!--第二种like,mapper中拼接,注意'%' #{} '%'之间有空格."%"或'%'不影响-->
<select id="selectLikeTwo" resultType="com.daihan.domain.Student">
select id,name,email,age from student where name like "%" #{name} "%"
</select>
注: 上述情况有时会”@P0“巴拉巴拉错误,应使用如下语句。
<!--第三种like,mapper中拼接,注意'%${}%'之间没有有空格。占位符需要$-->
<select id="selectLikeTwo" resultType="com.daihan.domain.Student">
select id,name,email,age from student where name like '%${name}%'
</select>
测试主方法:
@Test
public void testSelectLikeTwo(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
//准备like内容
String name="李";
List<Student> students = dao.selectLikeTwo(name);
for(Student stu:students){
System.out.println("学生:"+stu);
}
}
四、动态SQL(重点)
动态SQL:sql内容是变化的,可以根据条件获取不同的sql语句。主要是where部分发生变化。
动态SQL实现:使用的是MyBatis提供的标签,<if> ,<where>, <foreach>
1)if
if是判断条件的
语法:
<if test="判断一个Java对象的属性值">
<!--部分sql语句-->
</if>
dao包下XXXDao接口新增方法:
public interface StudentDao {
//动态sql,传参使用java对象
//if的使用
List<Student> selectStudentIf(Student student);
}
dao包下XXXDao.xml,增加
<!--
if
<if test="使用参数java对象的属性值做判断条件">
语句
</if>
满足if test条件时,把语句加到where后面
-->
<select id="selectStudentIf" resultType="com.daihan.domain.Student">
select id,name,email,age from student
where 1=1
<if test="name !=null and name !=''">
and name=#{name}
</if>
<if test="age>0">
or age>#{age}
</if>
</select>
测试程序:
@Test
public void testSelectStudentIf(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectStudentIf(new Student(1003, "李四", "123@163.com", 18));
for(Student stu:students){
System.out.println(stu);
}
}
2)where
where是用来包含多个if的,当多个if有一个成立的时候,where会自动增加一个where关键字,并去掉if中多余的and,or之类的。
dao包下XXXDao接口新增方法:
//where的使用
List<Student> selectStudentWhere(Student student);
dao包下XXXDao.xml,增加
<!--
where:<where><if>...</if></where>
-->
<select id="selectStudentWhere" resultType="com.daihan.domain.Student">
select id,name,email,age from student
<where>
<if test="name !=null and name !=''">
name=#{name}
</if>
<if test="age>0">
or age>#{age}
</if>
</where>
</select>
测试程序:
@Test
public void testSelectStudentWhere(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setAge(18);
List<Student> students = dao.selectStudentWhere(student);
for(Student stu:students){
System.out.println(stu);
}
}
3)choose、when
4)foreach
底层是字符串的拼接
集合中是基本数据类型
循环java中的数组,List集合的。主要用在sql的in语句中。
例如需要执行以下语句:select * from student where id in (1001,1002,1003)
dao包下XXXDao接口新增方法:
//foreach的使用
List<Student> selectForeachOne(List<Integer> idList);
dao包下XXXDao.xml,增加
<!--foreach使用:1、List<integer>-->
<select id="selectForeachOne" resultType="com.daihan.domain.Student">
select * from student where id in
<!--
collection,用来表示接口中方法参数类型,数组写array,List集合写list
item,自定义的表示数组和集合成员的变量
open,循环开始是字符
close,循环结束时字符
separator,集合成员之间的分割符
-->
<foreach collection="list" item="myid" open="(" close=")" separator=",">
#{myid}
</foreach>
</select>
测试程序:
@Test
public void testSelectForeachOne(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
List<Student> students = dao.selectForeachOne(list);
for(Student stu:students){
System.out.println(stu);
}
}
集合中是对象
dao包下XXXDao接口新增方法:
//foreach的使用2
List<Student> selectForeachTwo(List<Student> stuList);
dao包下XXXDao.xml,增加
重点是使用#{stu.id}
<select id="selectForeachTwo" resultType="com.daihan.domain.Student">
select * from student where id in
<foreach collection="list" item="stu" open="(" close=")" separator=",">
#{stu.id}
</foreach>
</select>
测试程序:
@Test
public void testSelectForeachTwo(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao dao=sqlSession.getMapper(StudentDao.class);
List<Student> stuList = new ArrayList<Student>();
for (int i=0;i<3;i++){
Student student = new Student();
student.setId(1001+i);
stuList.add(student);
}
List<Student> students = dao.selectForeachTwo(stuList);
for(Student stu:students){
System.out.println(stu);
}
}
代码片段
<sql/>
标签用于定义SQL片段,以使其他SQL标签复用。而其他标签使用该SQL片段,需要使用<include/>
子标签。该<sql/>
标签可以定义SQL语句中任何部分,所以<include/>
子标签放在动态SQL任意位置。
定义:
<sql id="studentSql">
语句
</sql>
使用:
<include refid="studentSql"/>
五、配置文件(了解)
主配置文件
文件中,顺序:properties、setings、typeAliases、plugins、environments
位置:模块-src-main-resources-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>
<settings>
<!--设置mybatis打印日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="mydev">
<environment id="mydev">
<transactionManager type="JDBC"/>
<!--
dataSource type指定数据源类型:POOLED、UPOOLED、JNDI
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="a123b456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/daihan/dao/StudentDao.xml"/>
</mappers>
</configuration>
使用属性配置文件管理连接数据
数据库的属性配置文件:把数据库连接信息放到单独一个文件中。和mybatis主配置文件分开。目的是便于修改,保存,处理多个数据库信息。
1、在resources目录中定义一个属性配置文件,xxx.properties
key一般使用多级目录,例如jdbc.mysql.driver
2、在mybatis的主配置文件中,使用<property>
指定文件位置
在需要使用值的地方,${}
主配置文件中:先指定properties文件路径,再使用文件
<?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文件的位置,从类的根路径开始-->
<properties resource="jdbc.properties"/>
<settings>
<!--设置mybatis打印日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="mydev">
<environment id="mydev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/daihan/dao/StudentDao.xml"/>
</mappers>
</configuration>
多个mapper文件
第一种方式
<mappers>
<mapper resource="com/daihan/dao/StudentDao.xml"/>
<mapper resource="com/daihan/dao/StudentDao.xml"/>
...
</mappers>
第二种方式,使用包名
name:xml文件所在包名
<package name="com.daihan.dao">
使用要求:
1、mapper文件名称需要和接口一样
2、mapper文件和dao接口需要在同一目录
六、扩展 ——PageHelper
做数据分页的。原本需要limit语句
使用步骤:
1、pom中加入maven依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
2、加入plugin配置,在<enviroments>
之前加入
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
</plugins>
具体使用:
调用dao接口方法查找前,先调用PageHelper静态方法starPage(x,y);显示第x页(从1开始),每页y个
PageHelper.starPage(1,3);
List<Student> studentList=studentDao.selectStudents();
处理枚举类型
注:
1、常见问题
- dao中的接口,于xml文件中的mapper的namespace对应