第一章 框架的概述
1、三层架构
MVC:web开发中,使用MVC架构模式,M:数据,V:视图,C:控制器
C控制器:接收请求,调用service对象,显示请求的处理结果,当前使用servlet作为控制器
V视图:现在使用jsp,html,css,js。显示请求的处理结果,把M中的数据显示出来
M数据:来自数据库mysql,来自文件,来自网络
MVC作用:
1)实现解耦合
2)让MVC各负其职
3)使得系统扩展性更好,更容易维护
三层架构:
1、界面层(视图层):接收用户的请求,调用service,显示请求的处理结果的,包含了jsp、html、servlet等对象,对应的包controller
2、业务逻辑层:处理业务逻辑,使用算法处理数据的,把数据返回给界面层,对应的是service包,和包中的很多的XXXservice类,例如:StudentService、OrderService、ShopService
3、持久层(数据库访问层):访问数据库,或者读取文件,访问网络。获取数据,对应的包是dao,dao包中很多的StudentDao,OrderDao,ShopDao等等
2、三层架构请求的处理流程
用户发起请求——>界面层——>业务逻辑层——>持久层——>数据库(MySQL)
3、为什么要使用这三层?
1、结构清晰、耦合度低、各层分工明确
2、可维护性高,可扩展性高
3、有利于标准化
4、开发人员可以只关注整个结构中的其中某一层的功能实现
5、有利于各层逻辑的复用
4、三层架构模式和框架
每一层对应着一个框架
1)界面层——SpringMVC框架
2)业务层——Spring框架
3)持久层——MyBatis框架
MyBatis框架:
MyBatis是一个优秀的基于java的持久层框架,内部封装了jdbc,开发者只需要关注sql语句本身,而不需要处理加载驱动、创建连接、创建statement、关闭连接
Spring框架:
Spring框架为了解决软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前非常复杂的企业级开发。Spring解决了业务对象,功能模块
SpringMVC框架:
SpringMVC属于SpringFrameWork3.0版本加入的一个模块,为Spring框架提供了构建Web应用程序的能力
5、框架
框架(framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构建实例间交互的方法:另一种认为,框架是可被应用开发者定制的应用骨架、模板
简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。从另一个角度来说框架是一个舞台,你在舞台上做表演。在框架基础上加入你要完成的功能
框架是安全的,可复用的,不断升级的软件
框架:就是一个软件,完成了部分的功能,软件中的类和类之间的方法调用都已经规定好了,通过这些可以完成某些功能,框架看做是模板
框架是对某一个方面有用的,不是全能的
6、框架解决的问题
1)框架能实现技术的整合
2)提供开发的效率,降低难度
框架要解决的最重要的一个问题是技术整合,在J2EE的框架中,有着各种各样的技术,不同的应用,系统使用不同的技术解决问题,需要从J2EE中选择不同的技术,而技术自身的复杂性,有导致更大的风险。企业在开发软件项目时,主要目的是解决业务问题,既要求企业负责技术本身,又要求解决业务问题,这是大多数企业不能完成的,框架把相关的技术融合在一起,企业开发可以集中在业务领域方面
另一个方面可以提供开发的效率
7、JDBC访问数据库的优缺点
优点:1、直观、好理解
缺点:
1、创建很多对象Connection,Statement,ResultSet
2、注册驱动
3、执行sql语句
4、把ResultSet转为Student,List集合
5、关闭资源
6、sql语句和业务逻辑代码混在一起
8、MyBatis框架
什么是MyBatis?是一个持久层框架
MyBatis框架:MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到GitHub
MyBatis解决的问题:减轻使用JDBC的复杂性,不用编写重复的创建Connection,Statement;不用编写关闭资源代码
直接使用java对象,表示结果数据,让开发者专注SQL的处理,其它分心的工作由MyBatis代劳
MyBatis可以完成:
1、注册数据库的驱动,例如Class.forName(“com.mysql.cj.jdbc.Driver”)
2、创建JDBC中必须使用的Connection,Statement,ResultSet对象
3、从xml中获取sql,并执行sql语句,把ResultSet结果转换为java对象
4、关闭资源
ResultSet.close(),Statement.close(),Connection.close()
MyBatis可以操作数据库,对数据执行增删改查,看做是高级的jdbc,解决jdbc的缺点
第二章 MyBatis框架快速入门
2.1 入门案例
MyBatis开发准备
下载MyBatis:https://github.com/mybatis/mybatis-3/releases
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
搭建MyBatis开发环境,实现第一个案例
(1)创建mysql数据库和表
数据库名ssm;表名student
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4OJrUqAe-1642483473066)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828134238544.png)]
(2)新建maven项目
(3)修改pom.xml
1)加入依赖mybatis依赖,mysql驱动,junit
2)在<build>加入资源插件
(4)创建实体类Student,定义属性,属性名和列名保持一致
(5)创建Dao接口,定义操作数据库的方法
(6)创建xml文件(mapper文件),写sql语句
mybatis框架推荐是把sql语句和java语句分开
mapper文件:定义和dao接口在同一目录,一个表一个mapper文件
(7)创建mybatis的主配置文件(xml文件):有一个,放在resources目录下
1)定义创建连接实例的数据源(DataSource)对象
2)指定其他mapper文件的位置
(8)创建测试的内容
使用main方法,测试mybatis访问数据库
也可以使用junit访问数据库
<build>
<resources>
<!--资源插件:处理src/main/java目录中的xml-->
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
<?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="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
约束文件:“http://mybatis.org/dtd/mybatis-3-mapper.dtd”
约束文件作用:定义和限制当前文件中可以使用的标签和属性,以及标签出现的顺序
mapper是根标签
namespace:命名空间,必须有值,不能为空,唯一值,推荐使用Dao接口的权限定名称,作用:参与识别sql语句的作用
在mapper里面可以写<insert>,<update>,<delete>,<select>标签
<insert>里面是insert语句,表示执行的insert操作
<update>里面是update语句
<delete>里面是delete语句
<select>里面是select语句
<!-- 查询一个学生Student
<select>:表示查询操作,里面是select语句
id:要执行的sql语句的唯一标识,是一个自定义字符串,推荐使用dao接口中的方法名称
resultType:告诉mybatis,执行sql语句,把数据赋值给哪个类型的java对象
resultType的值现在使用的java对象的全限定名称
-->
<select id="selectStudentById" resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where id=1001
</select>
主配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 配置数据源,创建Connection对象-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql//localhost:3306/ssm?useUnicode-true&characterEncoding-utf-8"/>
<property name="username" value="root"/>
<property name="password" value="westos"/>
</dataSource>
</environment>
</environments>
<!-- 指定其他mapper文件的位置,目的:找到其他文件的sql语句-->
<mappers>
<!-- 使用mapper的resource属性指定mapper文件的路径,这个路径是从target/classes路径开启的-->
<!-- 使用注意:resource="mapper"文件的路径,使用/分隔路径-->
<!-- 一个mapper resource指定一个mapper文件-->
<mapper resource="org/example/mybatis/dao/StudentDao.xml"/>
</mappers>
</configuration>
public class MyTest {
@Test
public void testSelectStudentById() throws IOException {
//调用mybatis某个对象的方法,执行mapper文件中的sql语句
//mybatis核心类:SqlSessionFactory
//1、定义mybatis主配置文件的位置,从类路径开始的相对路径
String config = "mybatis.xml";
//2、读取主配置文件,使用mybatis框架中的Resources类
InputStream inputStream = Resources.getResourceAsStream(config);
//3、创建SqlSessionFactory对象,使用SqlSessionFactoryBuilder类
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//4、获取SqlSession对象
SqlSession session = factory.openSession();
//5、指定要执行的sql语句的id
//sql的id = namespace+"."+select|update|insert|delete标签的id属性值
String sqlId = "org.example.mybatis.dao.StudentDao" + "." + "selectStudentById";
//6、通过SqlSession的方法,执行sql语句
Student student = session.selectOne(sqlId);
System.out.println("student = " + student);
//7、关闭SqlSession对象
session.close();
}
}
初次使用占位符
#{studentId}:占位符,表示从java程序中传入过来的数据
<select id="selectStudentById" resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where id=#{studentId}
</select>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r5qToowf-1642483473067)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828155936395.png)]
insert需要提交事务
日志功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vJ7DNfFk-1642483473068)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828160502771.png)]
2.2 概念
自动提交:当你的sql语句执行完毕后,提交事务,数据库更新操作直接保存到数据库
手动提交事务:在你需要提交事务的位置,执行方法,执行事务或者回滚事务
mybatis默认执行sql语句是手工提交事务模式,在做insert,update,delete后需要提交事务
session.commit()
如果传入给mybatis是一个java对象,使用#{属性名}获取此属性的值
属性值放到#{}占位符的位置,mybatis执行此属性对应的getXXX()
例如#{id},执行getId();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U5qFG4bx-1642483473069)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828185733066.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iDjDTugm-1642483473070)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828185806214.png)]
2.3Mybatis的一些重要对象
1)Resources:mybatis框架中的对象,一个作用读取主配置信息
2)SqlSessionFactoryBuilder:负责创建SqlSessionFactory对象
3)SqlSessionFactory:重要对象
SqlSessionFactory是重量级对象:创建此对象需要使用更多的资源和时间,在项目中有一个就可以了
SqlSessionFactory接口:作用是SqlSession的工厂,就是创建SqlSession对象
DefaultSessionFactory实现类
public class DefaultSqlSessionFactory implements SqlSessionFactory{}
SqlSessionFactory接口中的方法
openSession():获取一个默认的SqlSession对象,默认是需要手工提交事务的
openSession(boolean):boolean参数表示是否自动提交事务
true:创建一个自动提交事务的SqlSession
false:等同于没有参数的openSession
4)SqlSession对象
SqlSession对象是通过SqlSessionFactory获取的,SqlSession本身是接口
DefaultSqlSession实现类
public class DefaultSqlSession implements SqlSession{}
SqlSession作用是提供了大量的执行sql语句的方法
selectOne:执行sql语句,最多得到一行记录,多余一行是错误
selectList:执行sql语句,返回多行数据
selectMap:执行sql语句,得到一个Map结果
insert:执行insert语句
update:执行update语句
delete:执行delete语句
commit:提交事务
rollback:回滚事务
注意SqlSession对象不是线程安全的,使用的步骤:
①:在方法的内部,执行sql语句之前,先获取SqlSession对象
②:调用SqlSession的方法,执行sql语句
③:关闭SqlSession对象,执行SqlSession.close()
mybatis的底层是jdbc
2.4使用工具类和模板
创建mapper文件的模板
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fKaa5YkL-1642483473071)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828200448855.png)]
加号添加自定义模板
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtEHgKz7-1642483473073)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828201056999.png)]
创建主配置文件的模板
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Mqrea8w-1642483473074)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828201834355.png)]
创建工具类MyBatisUtil
/**
* 工具类:创建SqlSession对象
*/
public class MyBatisUtil {
private static SqlSessionFactory factory = null;
static {
String config = "mybatis.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(config);
factory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//创建方法,获取SqlSession对象
public static SqlSession getSqlSession(){
SqlSession session = null;
if (factory != null){
session = factory.openSession();//openSion(true);
}
return session;
}
}
@Test
public void testSelectById(){
//1、获取SqlSession
SqlSession session = MyBatisUtil.getSqlSession();
//2、指定sqlid
String sqlId = "org.example.mybatis.dao.StudentDao" + "." + "InsertStudent";
//3、执行SqlSession的方法,执行sql语句
session.insert(sqlId,new Student(1005,"hhahhvsah","hahsak@qq.com",78));
session.commit();
//4、关闭SqlSession对象
session.close();
}
查询所有
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HHc0GvQ1-1642483473074)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828204628579.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gJi0Vl0N-1642483473076)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828204653535.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LCvAxEFs-1642483473076)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210828204726087.png)]
使用传统的dao执行sql
public class StudentDaoImpl implements StudentDao {
@Override
public Student selectStudentById(Integer id) {
SqlSession session = MyBatisUtil.getSqlSession();
String sqlId = "org.example.mybatis.dao.StudentDao" + "."+ "selectStudentById";
Student student = session.selectOne(sqlId, id);
session.close();
return student;
}
@Override
public int InsertStudent(Student student) {
SqlSession session = MyBatisUtil.getSqlSession();
String sqlId = "org.example.mybatis.dao.StudentDao" + "."+"InsertStudent";
int hah = session.insert(sqlId, student);
session.commit();
session.close();
return hah;
}
@Override
public List<Student> selectAllStudent() {
SqlSession session = MyBatisUtil.getSqlSession();
String sqlId = "org.example.mybatis.dao.StudentDao" + "."+ "selectAllStudent";
List<Student> students = session.selectList(sqlId);
session.close();
return students;
}
}
public class StudentDaoImplTest extends TestCase {
private StudentDaoImpl studentDao = new StudentDaoImpl();
public void testSelectStudentById() {
Student student = studentDao.selectStudentById(1002);
System.out.println("student = " + student);
}
public void testInsertStudent() {
int i = studentDao.InsertStudent(new Student(1006, "ahhvsah", "hsak@qq.com", 78));
System.out.println("i = " + i);
}
public void testSelectAllStudent() {
List<Student> students = studentDao.selectAllStudent();
for (Student stu:students){
System.out.println("stu = " + stu);
}
}
}
测试方法中:调用dao的方法
Student student = dao.selectById(1002);
1)dao:通过反射能够得到全限定类型名称
dao是StudentDao类型的,全限定类型名称org.example.mybatis.dao.StudentDao
2)selectById:dao中的方法名称,方法名称就是mapper文件中标签的id
通过dao.selectById()能得到sqlId=“com.example.mybatis.dao.StudentDao.selectById”;
3)确定调用SqlSession的那个方法
1、根据dao接口的方法返回类型,如果返回是一个对象,例如Student,调用SqlSession.selectOne();
如果dao接口中的方法返回List,调用SqlSession的selectList();
2、根据mapper文件中的标签,如果标签是<insert>,调用SqlSession.insert()方法
mybatis代理的说明
mybatis框架,发现使用dao的方法调用能确定执行sql语句的必要信息,mybatis简化dao对象的实现
由mybatis框架在程序执行期间,根据你的Dao接口,创建一个内存中的接口的实现类对象
mybatis把这个技术叫做dao技术(动态代理,dao的动态代理)
dao代理技术:由mybatis创建StudentDao接口的实现类StudentDaoImpl,使用框架创建的StudentDaoImpl代替你自己手动实现的StudentImpl类的功能,不用开发人员写dao接口的实现类
使用dao的代理要求:
1、mapper文件中的namespace:必须是dao接口的全限定名称
2、mapper文件中标签的id是dao接口中的方法名称(一模一样的)
2.5dao代理
mybatis提供代理:mybatis创建Dao接口的实现类对象,完成对sql语句的执行,mybatis创建一个对象代替你的dao实现类功能
使用mybatis代理要求
1)mapper文件中的namespace一定是dao接口的全限定名称
2)mapper文件中标签的id是dao接口方法名称
mybatis代理实现方式
使用SqlSession对象的方法getMapper(dao.class)
例如:现在有StudentDao接口
SqlSession session = MyBatisUtils.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.calss);
Student student = dao.selectById(1001);
//上面代码中
StudentDao dao = session.getMapper(StudentDao.calss);
//等同于
StudentDao dao = new StudentDaoImpl();
@Test
public void testInserttStudentById() throws IOException {
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
Student student = dao.selectStudentById(1003);
System.out.println("student = " + student);
session.close();
}
不需要StudentDao实现类了
@Test
public void testSelectById(){
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
int i = dao.InsertStudent(new Student(1007, "jajc", "jdnacj@qq.com", 18));
System.out.println("i = " + i);
session.commit();
session.close();
}
@Test
public void testSelectAllStudent(){
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
List<Student> students = dao.selectAllStudent();
students.forEach(student -> {
System.out.println("student = " + student);
});
session.close();
}
(1)去掉Dao接口的实现类
(2)getMapper获取代理对象
只需调用SqlSeesion的getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定Dao接口类的class值
SqlSession session = factory.openSession();
StudentDao dao = session.getMapper(StudentDao.class);
使用工具类:
StudentDao studentDao = MyBatisUtil.getSqlSession().getMapper(StudentDao.class);
(3)使用Dao代理对象方法执行sql语句
第三章 mybatis的dao代理
3.2 深入理解参数
从java代码中把参数传递到mapper.xml文件
理解参数是:通过java程序把数据传入到mapper文件中的sql语句
参数主要是指dao接口方法的形参
3.2.1 parameterType
parameterType:接口中方法参数的类型,类型的完全限定名或别名。这个属性是可选的,因为mybatis可以推断出具体传入语句的参数,默认值为未设置(unset)。接口中方法的参数从java代码传入到mapper文件的sql语句
<select>,<insert>,<update>,<delete>都可以使用parameterType指定类型
parameterType:表示参数的类型,指定dao方法的形参数据类型,这个形参的数据类型给mybatis使用,mybatis在给sql语句的参数赋值时使用,PreparedStatement.setXXX(位置,值)
parameterType:指定dao接口形参的类型,这个属性的值可以使用java类型的全限定名称或者mybatis定义的别名
<select id="selectById" parameterType="java.lang.Integer" resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where id=#{studentId}
</select>
mybatis执行的sql语句:select id,name,email,age from student where id=?
?是占位符,使用jdbc中的PreparedStatement执行这样的sql语句
PreparedStatement pst = conn.preparedStatement("select id,name,email,age from student where id=?")
给?位置赋值
参数是Integer,执行pst.setInt(1,1005);
参数是String,执行pst.setString(1,“1005”);
第一种用法:java类型的全限定类型名称 parameterType=”java.lang.Integer"
第二种用法:mybatis定义的java类型的别名
官方文档
parameterType可以不写,mybatis通过反射机制可以获取dao接口方法参数的类型
3.2.2 一个简单参数
Dao接口中方法的参数只有一个简单类型(java基本类型和String),占位符#{任意字符},和方法的参数名无关
接口方法:Student selectById(int id);
mapper文件:获取这个参数值,使用#{任意字符}
3.2.3 dao接口方法有多个简单类型的参数
@Param:命名参数,在方法的形参前面使用的,定义参数名,这个名称可以用在mapper文件中
dao接口,方法的定义
/**
* 多个简单类型的参数
* 使用@Param命名参数,注解是mybatis提供的
* 位置:在形参定义的前面
* 属性:value自定义的参数名称
*/
List<Student> selectByNameOrAge(@Param("myname") String name,
@Param("myage") Integer age);
mapper文件
<!--
多个简单类型的参数
当使用了@Param命名后,例如@Param("myname")
在mapper中,使用#{命名的参数},例如#{myname}
-->
<select id="selectByNameOrAge" resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>
3.2.4 dao接口方法使用一个对象作为参数
方法的形参是一个java对象,这个java对象表示多个参数,使用对象的属性值作为参数使用
/**
* 一个java对象作为参数(对象有属性,每个属性有set,get方法)
*/
List<Student> selectByObject(Student student);
mapper文件
<!--
一个java对象作为方法的参数,使用对象的属性作为参数值使用
简单的语法:#{属性名},mybatis调用对象的getXXX()方法获取属性值
-->
<select id="selectByObject" resultType="org.example.mybatis.pojo.Student">
insert into student values (#{id},#{name},#{email},#{age})
</select>
<select id="selectByObject" resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where name=#{name} or age=#{age}
</select>
多个参数——使用对象
使用java对象传递参数,java的属性值就是sql需要的参数值,每一个属性就是一个参数
语法格式
#{property,javaType=java中数据类型名,jdbcType=数据类型名称}
javaType,jdbcType的类型MyBatis可以检测出来,一般不需要设置,常用格式#{property}
<select id="selectByObject" resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where name=#{name,javaType=java.lang.String,jdbcType=VARCHAR} or age=#{age,javaType=java.lang.Integer,jdbcType=INTEGER}
</select>
多个参数——按位置
参数位置从0开始,引用参数语法#{arg位置},第一个参数是#{arg0},第二个是#{arg1}
注意:mybatis-3.3版本和之前的版本使用#{0},#{1}方式,从mybatis3.4开始使用#{arg0}方式
接口方法:List<Student> selectByNameAndAge(String name,int age);
mapper文件:
<select id="selectByNameAndAge" resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where name=#{arg0} or age=#{arg1}
</select>
多个参数——使用Map
Map集合可以存储多个值,使用Map向mapper文件一次传入多个参数,Map集合使用String的key
Object类型的值存储参数,mapper文件使用#{key}引用参数值
例如:
Map<String,Object> data = new HashMap<String,Object>(){{
put("myname","李力");
put("myage",20);
}}
接口方法:
List<Student> selectStudentByMap(Map<String,Object> map);
在mapper文件中,获取map的值,是通过key获取的,语法:#{key}
<select id="selectByNameAndAge" resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>
更新
<update id="updateStudent">
update student set name=#{name},email=#{email} where id=#{id}
</update>
#和$
#占位符:告诉mybatis使用实际的参数值代替,并使用PrepareStatement对象执行sql语句,#{…}代替sql语句的“?",这样做更安全,更迅速,通常也是首选做法
mapper文件
<select id="selectByNameAndAge" resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>
转为MyBatis的执行是:
String sql = "select id,name,email,age from student where id=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,1005);
ResultSet rs = ps.executeQuery();
#{}特点:
1)使用的PrepareStatement对象,执行sql对象,效率高
2)使用的PrepareStatement对象,能避免sql语句,sql语句执行更安全
3)#{}常常作为列值使用的,位于等号的右侧,#{}位置的值和数据类型有关的
$占位符:语法${字符}
mybatis执行${}占位符的sql语句
<select id="selectById" parameterType="integer"
resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where id=${studentId}
</select>
${} 表示字符串连接,把sql语句的其他内容和${}内容使用字符串(+)连接的方式连在一起
String sql = "select id,name,email,age from student where id=” + "1001";
mybatis创建Statement对象,执行sql语句
Statement stmt = conn.createStatement(sql);
ResultSet rs = stmt.executeQuery();
${}的特点
1)使用Statement对象,执行sql语句,效率低
2)${}占位符的值,使用的字符串连接方式,有sql注入的风险,有代码安全问题
3)${}数据是原样使用的,不会区分数据类型
4)${}常用作表名或者列名,在能保证数据安全的情况下使用${}
//$占位符的使用,使用@Param命名
List<Student> querySudent(@Param("myname") String name);
使用$占位符表示表名或者列名
3.3 封装MyBatis输出结果
封装输出结果:MyBatis执行sql语句,得到ResultSet,转为java对象
3.3.1 resultType
resultType:执行sql得到ResultSet转换的类型,使用类型的完全限定名或别名,注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。resultType和resultMap,不能同时使用
resultType属性:在执行select时使用,作为<select>标签的属性出现的
resultType:表示结果类型,mysql执行sql语句,得到java对象的类型,它的值有两种1)java类型的全限定名称,2)使用别名
1)resultType表示自定义对象
<select id="selectByNameAndAge" resultType="org.example.mybatis.pojo.Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>
resultType:现在使用java类型的全限定名称,表示的意思:mybatis执行sql,把ResultSet中的数据转为Student类型的对象。
mybatis会做以下操作:
1、调用org.example.mybatis.pojo.Student的无参数构造方法,创建对象
Student student = new Student(); //使用反射创建对象
2、同名的列赋值给同名的属性
student.setId(rs.getInt("id"));
student.setName(rs,getString("name"));
3、得到java对象,如果dao接口返回值是List集合,mybatis把student对象放入到List集合
所以执行Student mystudent = dao.selectById(1001); 得到数据库中id=1001这行数据
这行数据的列值,赋给了mystudent对象的属性,你能得到mystudent对象,就相当于是id=100这行数据
2)resultType表示简单类型
dao方法
long countStudent();
mapper文件
<!-- 执行sql语句,得到的是一个值(一行一列)-->
<select id="countStudent" resultType="java.lang.Long">
select count(*) from student
</select>
3)resultType为Map类型
sql的查询结果作为Map的key和value,推荐使用Map<Object,Object>
注意:Map作为接口返回值,sql语句的查询结果最多只能有一条记录,大于一条记录是错误
执行sql语句得到一个Map结构数据,mybatis执行sql,把ResultSet转为map
sql执行结果,列名做map的key,列值作为value
sql执行得到是一行记录,转为map结构是正确的
dao方法:
Map<Object,Object> selectReturnMap(int id);
mapper文件:
<select id="selectReturnMap" resultType="java.util.HashMap">
select name,email,from student where id=#{studentId}
</select>
3.3.2 resultMap
resultMap可以自定义sql的结果和java对象属性的映射关系,更灵活的把列值赋值给指定属性
常用在列名和java对象属性名不一样的情况
用法:先定义,再使用
1、先定义resultMap标签,指定列名和属性名称对应关系
2、在select标签使用resultMap属性,指定上面定义的resultMap的id值
<!-- 定义resultMap
id:给resultMap的映射关系起个名称,唯一值
type:java类型的全限定名称
-->
<resultMap id="studentMap" type="org.example.mybatis.pojo.Student">
<!-- 定义列名和属性名的对应-->
<!-- 主键类型使用id标签-->
<id column="id" property="cid" />
<!-- 非主键类型使用result标签-->
<result column="name" property="cname" />
<!-- 列名和属性名相同不用定义-->
<result column="email" property="email" />
<result column="age" property="age" />
</resultMap>
使用resultMap属性,指定映射关系的id
<select id="selectStudentById" resultMap="studentMap">
select id,name,email,age from student where id=#{studentId}
</select>
resultMap和resultType不能同时使用,二选一
3.3.3 实体类属性名和列名不同的处理方式
(1)使用列别名和<resultType>
步骤:
1、创建新的实体类PrimaryStudent
package org.example.pojo;
/**
* <p>Description:实体类</p>
* <p>Company:http://www.tyx.com
*/
public class PrimaryStudent{
private Integer stuId;
private String stuName;
private Integer stuAge;
//set,get方法
}
2、接口方法
List<PrimaryStudent> selectUserFieldAlias(QueryParam param);
mapper文件
<!-- 使用列别名,解决列名和属性名不同的问题-->
<select id="selectById" resultType="org.example.mybatis.pojo.Student">
select id stuId,name stuName,age stuAge from student where id=#{stuid}
</select>
(2)使用resultMap:自定义列名和属性名称对应关系
3.4 自定义别名
mybatis提供的对java类型定义简短、好记名称
自定义别名的步骤:
1)在mybatis主配置文件,使用typeAliase标签声明别名
2)在mapper文件中,resultType=“别名”
声明别名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cKQUyDGP-1642483473078)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210829161006841.png)]
放在settings语句的后面
<!--
第一种语法格式
type:java类型的全限定名称(自定义类型)
alias:自定义别名
-->
<typeAliases>
<typeAlias type="org.example.mybatits.pojo.Student" alias="stu"/>
</typeAliases>
mapper文件中使用
resultType=“别名"
优点:别名可以自定义
缺点:每个类型必须单独定义
<!-- 第二种方式
name:包名,mybatis会把这个包中所有类名作为别名(不用区分大小写)
优点:使用方便,一次给多个类定义别名
缺点:别名不能自定义,必须是类名
-->
<package name="org.example.mybatis.pojo"/>
建议:不用别名
模糊
模糊查询的实现有两种方式,一是java代码中给查询数据加上”%“;二是在mapper文件sql语句的条件位置加上”%“
(推荐使用)第一种方式:在java程序中,把like的内容组装好,把这个内容传入到sql语句
dao方法
List<Student> selectLikeOne(@Param("name") String name);
mapper文件
<select id="selecLikeOne" resultMap="studentMap">
select * from student where name like #{name}
</select>
String name = "%李%";
第二种方式:在sql语句中,组织like的内容
sql语句中like的格式:where name like “%“空格#{name}空格”%”
第四章 MyBatis框架动态SQL
动态SQL,通过MyBatis提供的各种标签对条件作出判断以实现动态拼接SQL语句。这里的条件判断使用的表达式为OGNL表达式。常用的动态SQL标签有<if>、<where>、<choose/>、<foreach>等
MyBatis的动态SQL语句,与JSTL的语句非常相似
什么是动态sql:同一个dao的方法,根据不同的条件可以表示不同的sql语句,主要是where部分有变化
使用mybatis提供的标签,实现动态sql的能力
使用动态sql时,dao方法的形参使用java对象
动态SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询,提交的查询条件不同,执行的SQL语句不同,若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的sql语句。此时,可使用动态sql来解决这样的问题
4.1 if
语法
<if test="boolean判断结果">
sql代码
</if>
多个if可以同时存在,但没有else
mapper文件中
<select id="selectStudent" resultType="org.example.mybatits.pojo.Student">
select * from student
<if test="条件">
sql语句
</if>
</select>
test:使用对象的属性值作为条件
<select id="selectIf" resultType="org.example.mybatits.pojo.Student">
select * from student
where
<if test="name != null and name != ''">
name = #{name}
</if>
<if test="age > 0">
or age < #{age}
</if>
</select>
多条件查询时使用动态sql和实体
在mapper的动态SQL中若出现大于号(>)、小于号(<)、大于等于号(>=)、小于等于号(<=)等符号,最好将其转换为实体符号。否则,XML可能会出现解析出错问题
特别是对于小于号(<),在XML中是绝不能出现的,否则解析mapper文件会出错
实体符号表:
< | 小于 | < |
---|---|---|
> | 大于 | > |
>= | 大于等于 | &get;= |
<= | 小于等于 | <= |
4.2 where标签
使用if标签时,容易引起sql语句语法错误,使用where标签解决if产生的语法问题
使用时,先写where,里面时一个或多个if标签,当有一个if标签判断条件为true,where标签会转为WHERE关键字,附加到sql语句的后面。如果if没有一个条件为true,忽略where和里面的if
语法:
<where>
<if test="条件1">sql语句1</if>
<if test="条件2">sql语句2</if>
</where>
<select id="selectWhere" resultType="org.example.mybatits.pojo.Student">
select * from student
<where>
<if test="name != null and name !=''">
or name = #{name}
</if>
<if test="age>0">
or age < #{age}
</if>
</where>
</select>
where标签删除和它最近的or或者and
4.3 foreach标签
<foreach/>标签用于实现对于数组与集合的遍历,对其使用,需要注意:
- collection表示要遍历的集合类型,list,array等
- open、close、separator为对遍历内容的SQL拼接、
使用foreach可以循环数组、list集合,一般使用在in语句中
语法:
<foreach collection="集合类型" open="开始的字符" close="结束的字符" item="集合中的成员" separator="集合成员之间的分隔符">
#{item的值}
</foreach>
标签属性:
collection:表示循环的对象是数组还是list集合,如果dao接口方法的形参是数组,collection=”array“,如果dao接口形参是List,collection=”list“
open:循环开始的字符sql.append("(");
close:循环结束时字符sql.append(")");
item:集合的成员,自定义的变量 Integer item = idlist.get(i);
//item是集合成员
separator:集合成员之间的分隔符sql.append(",");
//集合成员之间的分隔符
#{item的值}:获取集合成员的值
(1)遍历List<简单类型>
表达式中的List使用list表示,其大小使用list.size表示
dao方法:
List<Student> selectForeachOne(List<Integer> idlist);
mapper文件:
<select id="selectForeachOne" resultType="org.example.mybatits.pojo.Student">
select * from student
<if test="list != null and list.size()>0">
where id in
<foreach collection="list" open="(" close=")" separator="," item="myid">
#{myid}
</foreach>
</if>
</select>
(2)foreach对象类型的List
dao方法
List<Student> selectForeach(List<Student> studentList);
mapper文件
<select id="selectForeachOne" resultType="org.example.mybatits.pojo.Student">
select * from student
<if test="list != null and list.size()>0">
where id in
<foreach collection="list" open="(" close=")" separator="," item="stu">
#{stu.id}
</foreach>
</if>
</select>
4.4 动态SQL之代码片段
<sql/>标签用于定义SQL片段,以便其它SQL标签复用,而其他标签使用该SQL片段,需要使用<include/>子标签,该<sql/>标签可以定义SQL语句中的任何部分,所以<include/>子标签可以放在动态SQL的任何位置
sql标签表示一段sql代码,可以是表名,几个字段,where条件都可以,可以在其他地方复用sql标签的内容
使用方式:
1)在mapper文件中定义sql代码片段<sql id="唯一字符串">部分sql语句</sql>
2)在其他的位置,使用include标签引用某个代码片段
接口方法:
List<Student> selectStudentSqlFragment(List<Student> stuList);
mapper文件:
<!--创建sql片段id:片段的自定义名称-->
<sql id="studentSql">
select id,name,email,age from student
</sql>
<select id="selectForeachOne" resultType="org.example.mybatits.pojo.Student">
<include refid="studentSql"/>
<if test="list != null and list.size()>0">
where id in
<foreach collection="list" open="(" close=")" separator="," item="stu">
#{stu.id}
</foreach>
</if>
</select>
<sql id="studentFieldList">
id,name,email
</sql>
<select id="selectForeachOne" resultType="org.example.mybatits.pojo.Student">
select <include refid="selectFieldList"/> from student
<if test="list != null and list.size()>0">
where id in
<foreach collection="list" open="(" close=")" separator="," item="stu">
#{stu.id}
</foreach>
</if>
</select>
第五章 MyBatis配置文件
mybatis配置文件有两大类:1、mybatis主配置文件;2、mybatis的mapper文件
1、mybatis主配置文件,提供mybatis全局设置的,包含的内容:日志、数据源、mapper文件位置
2、mapper文件:写sql语句的,一个表一个mapper文件
5.1 settings部分
settings是mybatis的全局设置,影响整个mybatis的运行,这个设置一般使用默认值就可以了
官方文档
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sYTdbAk5-1642483473078)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830091713115.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V8W2C7JT-1642483473080)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830091810507.png)]
5.2 typeAliase别名
设置别名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ATmYWVM8-1642483473080)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830091920321.png)]
5.3 配置环境
environments:环境标签,在他里面可以配置多个environment
属性:default,必须是某个environment的id属性值,表示mybatis默认连接的数据库
environment:表示一个数据库的连接信息
属性:id自定义的环境的标识,唯一值
transactionManager:事务管理器
属性:type表示事务管理器的类型
属性值:1)JDBC:使用Connection对象,由mybatis自己完成事务的处理
2)MANAGED:管理,表示把事务的处理交给容器实现(由其他软件完成事务的提交,回滚)
datasource:数据源,创建的Connection对象,连接数据库
属性:type数据源的类型
属性值:1)POOLED,mybatis会在内存中创建PooledDataSource类,管理多个Connection连接对象,使用的连接池
2)UNPOOLED,不使用连接池,mybatis创建一个UnPooledDataSource这个类,每次执行sql语句先创建Connection对象,再执行sql语句,最后关闭Connection
3)JNDI:java的命名和目录服务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-71oDFmif-1642483473081)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830092041048.png)]
5.4 使用数据库属性配置文件
需要把数据库的配置信息放到一个单独文件中,独立管理,这个文件扩展名是properties,在这个文件中,使用自定义的key=value的格式表示数据
使用步骤:
1)在resource目录中,创建xxxx.properties
2)在文件中,使用key=value的格式定义数据
例如:jdbc.url=jdbc:mysql://localhost:3306/test
3)在mybatis主配置文件,使用<property>标签引用外部的属性配置文件
4)在使用值的位置,使用${key}获取key对应的value(等号右侧的值)
<configuration>
<!-- 使用外部属性配置文件 -->
<properties resource="jdbc.properties" /> 使用类路径之下的属性文件
resource:指定类路径下的某个属性配置文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N9YYhvk4-1642483473081)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830100535348.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z96L0SMN-1642483473082)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830100634889.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J6hFs6Y1-1642483473082)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830100655455.png)]
5.5 mapper标签
使用mapper指定其他mapper文件的位置
mapper标签使用的格式有两个常用的方式
第一种方式:resource=“mapper文件的路径”
优点:文件清晰,加载的文件是明确的,文件的位置比较灵活
缺点:文件比较多,代码量会比较大,管理难度大
<mappers>
<mapper resource="org/example/mybatis/dao/StudentDao.xml"/>
</mappers>
第二种方式:使用<package>
name:包名,mapper文件所在的包名
特点:把这个包中的所有mapper文件,一次加载
<package name="org.example.mybatis.dao"/>
使用要求:
1、mapper文件和dao接口在同一目录
2、mapper文件和dao接口名称完全一致
第六章 扩展
6.1 PageHelper
一个插件
6.1.1 MyBatis通用分页插件
https://github.com/pagehelper/Mybatis-PageHelper
(1)maven坐标获取
(2)加入plugin配置
在<environments>之前加入
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
(3)PageHelper对象
查询语句之前调用PageHelper startPage静态方法
除了PageHelper startPage方法外,还提供了类似用法的PageHelper.offsetPage方法
在你需要进行分页的MyBatis查询方法前调用PageHelper.startPage静态方法即可,紧跟在这个方法后的第一个MyBatis查询方法会被进行分页
@Test
public void testTest() throws IOException {
//获取第1页,3条内容
PageHelper.startPage(1,3);
List<Student> studentList = studentDao.selectStudents();
studentList,forEach(stu -> System.out.println(stu));
}
PageHelper做数据分页,在你的select语句后面加入分页的sql内容,如果你使用的mysql数据库,它就是在select * from studetn
后面加入limit语句
使用步骤:
1、加入依赖pageHelper依赖
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.1</version>
</dependency>
2、在mybatis主配置文件,加入plugin声明
3、在select语句之前,调用PageHelper.startPage(页码,每页大小)
个常用的方式
第一种方式:resource=“mapper文件的路径”
优点:文件清晰,加载的文件是明确的,文件的位置比较灵活
缺点:文件比较多,代码量会比较大,管理难度大
<mappers>
<mapper resource="org/example/mybatis/dao/StudentDao.xml"/>
</mappers>
第二种方式:使用<package>
name:包名,mapper文件所在的包名
特点:把这个包中的所有mapper文件,一次加载
<package name="org.example.mybatis.dao"/>
使用要求:
1、mapper文件和dao接口在同一目录
2、mapper文件和dao接口名称完全一致
第六章 扩展
6.1 PageHelper
一个插件
6.1.1 MyBatis通用分页插件
https://github.com/pagehelper/Mybatis-PageHelper
(1)maven坐标获取
(2)加入plugin配置
在<environments>之前加入
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
(3)PageHelper对象
查询语句之前调用PageHelper startPage静态方法
除了PageHelper startPage方法外,还提供了类似用法的PageHelper.offsetPage方法
在你需要进行分页的MyBatis查询方法前调用PageHelper.startPage静态方法即可,紧跟在这个方法后的第一个MyBatis查询方法会被进行分页
@Test
public void testTest() throws IOException {
//获取第1页,3条内容
PageHelper.startPage(1,3);
List<Student> studentList = studentDao.selectStudents();
studentList,forEach(stu -> System.out.println(stu));
}
PageHelper做数据分页,在你的select语句后面加入分页的sql内容,如果你使用的mysql数据库,它就是在select * from studetn
后面加入limit语句
使用步骤:
1、加入依赖pageHelper依赖
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.1</version>
</dependency>
2、在mybatis主配置文件,加入plugin声明
3、在select语句之前,调用PageHelper.startPage(页码,每页大小)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-igblaRuw-1642483473083)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210830104706119.png)]