SSM:Spring SpringMVC Mybatis
SSH: Spring struts2 hibernate
1 Mybatis 1.1 原始的jdbc操作- 加载驱动
- 获取链接
- 编写sql语句
- 创建执行器 statement
- 执行CRUD
- 释放资源
原始jdbc存在的问题:
- 数据库连接创建 释放频繁造成系统资源的浪费从而影响系统性能
- sql语句在代码中是硬编码 造成代码不易维护 实际应用sql变化的可能性比较大 sql变动需要改变Java代码
- 查询操作时,需要手动将接过机中的数据封装到实体中。插入数据的时候,需要手动的将实体的数据设置到sql语句的占位符的位置。
解决方案:
- 使用数据库连接池初始化连接资源
- sql语句抽取到xml配置文件中
- 使用反射技术,自动将实体与表进行属性和字段的自动映射
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
采用的思想ORM 。对jdbc进行封装,屏蔽了jdbc api底层的访问细节,不需要与jdbc api打交道 就可以完成数据的持久化操作
2.1 mybatis 快速入门1 引入依赖
org.mybatis
mybatis
3.5.7
mysql
mysql-connector-java
5.1.48
junit
junit
4.13.2
test
2 创建数据库表
3 编写User的实体
public class User {
private int id;
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + ''' +
", password='" + password + ''' +
'}';
}
}
4 配置mybatis
5 创建Dao接口 UserDao
public interface UserDao {
List findAll();
}
6创建映射文件UserDao.xml
2.2 小结select * from User
- 添加mybatis的依赖(数据库的连接驱动)
- 创建了数据库表
- 创建了实体
- 创建mybatis的主配置文件:连接数据库的属性
- 配置文件的名称可以随意,位置必须位于resources目录下
- 连接属性必须配置正确
- 编写dao接口
- 编写dao接口的映射文件:sql语句
- 映射文件的位置必须位于resources目录下 并且他的层级关系要和dao接口保持一致(在resources目录下创建层级结构的时候,创建的是directory 而且要一个一个创建,不能像创建包一样使用点分割一次写完)
- 映射文件的名称必须和dao接口的名称保持一致 扩展名为.xml
- namespace是dao接口的全类名
- sql语句的id是dao接口的方法名
- 测试
注意事项:在mybatis中 dao层的命名。一般命名为XXXMapper
2.3 使用mybatis完成增删改操作public interface UserMapper {
List findAll();
void add(User user);
void update(User user);
void delete(int id);
}
映射文件
3 mybatis插件free-idea-mybatis是一款增强idea对mybatis支持的插件,主要功能如下:
生成mapper xml文件
快速从代码跳转到mapper及从mapper返回代码
mybatis自动补全及语法错误提示
集成mybatis generator gui界面
根据数据库注解,生成swagger model注解
作用一:快速从代码跳转到mapper及从mapper返回代码
作用二:可以逆向生成实体。dao。mapper
4 mybatis的核心配置文件 4.1 environments:- 默认使用的环境 ID(比如:default=“development”)。
- 每个 environment 元素定义的环境 ID(比如:id=“development”)。
- 事务管理器的配置(比如:type=“JDBC”)。
- 数据源的配置(比如:type=“POOLED”)。
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
- JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
- MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为
数据源(dataSource)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
- 大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。UNPOOLED 类型的数据源仅仅需要配置以下 5 种属性:
- driver – 这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类)。
- url – 这是数据库的 JDBC URL 地址。
- username – 登录数据库的用户名。
- password – 登录数据库的密码。
- defaultTransactionIsolationLevel – 默认的连接事务隔离级别。
- defaultNetworkTimeout – 等待数据库操作完成的默认网络超时时间(单位:毫秒)。查看 java.sql.Connection#setNetworkTimeout() 的 API 文档以获取更多信息。
作为可选项,你也可以传递属性给数据库驱动。只需在属性名加上“driver.”前缀即可,例如:
- driver.encoding=UTF8
这将通过 DriverManager.getConnection(url, driverProperties) 方法传递值为 UTF8 的 encoding 属性给数据库驱动。
POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
除了上述提到 UNPOOLED 下的属性外,还有更多属性用来配置 POOLED 的数据源:
- poolMaximumActiveConnections – 在任意时间可存在的活动(正在使用)连接数量,默认值:10
- poolMaximumIdleConnections – 任意时间可能存在的空闲连接数。
- poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
- poolTimeToWait – 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。
- poolMaximumLocalBadConnectionTolerance – 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过 poolMaximumIdleConnections 与 poolMaximumLocalBadConnectionTolerance 之和。 默认值:3(新增于 3.4.5)
- poolPingQuery – 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。
- poolPingEnabled – 是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。
- poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。
JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用。这种数据源配置只需要两个属性:
- initial_context – 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么将会直接从 InitialContext 中寻找 data_source 属性。
- data_source – 这是引用数据源实例位置的上下文路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。
和其他数据源配置类似,可以通过添加前缀“env.”直接把属性传递给 InitialContext。比如:
- env.encoding=UTF8
这就会在 InitialContext 实例化时往它的构造方法传递值为 UTF8 的 encoding 属性。
4.2 properties数据库连接属性文件
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/lanqiao username=root password=root
mybatis主配置文件中使用属性文件
4.3 setting读取属性配置文件
日志
引入log4j的依赖
log4j log4j 1.2.17
log4j的配置
# 全局日志配置 log4j.rootLogger=ERROR, stdout # MyBatis 日志配置 log4j.logger.cn.lanqiao.mapper.UserMapper=TRACE # 控制台输出 log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
日志的级别
开发阶段一般使用debug
生产环境一般使用error
通过输入的日志 我们可以明确的知道当前执行的sql的情况,
这里的#{}会被解析为? 所以使用的是preparestaement 有效预防sql注入
4.4 类型别名(typeAliases)使用
同时还支持为位于同一包下的所有类进行统一设置
4.5映射器(mappers)
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等
5 mybatis的相应API
//加载主配置文件 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); //获取sqlsessionFactory对象 产生sqlsession SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //获取sqlsession对象 sqlSession = sqlSessionFactory.openSession(); // Listusers = sqlSession.selectList("findAll"); //获取dao对象 mapper = sqlSession.getMapper(UserMapper.class);
SqlSessionFactoryBuilder使用核心配置文件 构建一个SqlSessionFactory
SqlSessionFactory是用来创建sqlSession
openSession() 默认开启一个事务 但是事务不会自动提交 意味着需要手动提交或回滚事务 此时数据才能持久化到数据库中
openSession(boolean b ) 参数为是否自动提交 如果为true 则数据库会自动提交事务
sqlSession 是一个非常强大的类 执行语句 提交事务 回滚事务 获取映射器的实例的方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wnv7wpky-1635751127160)(assets/image-20211009155401411.png)]
6 mybatis的底层实现原理public class UserMapperIMPL implements UserMapper {
@Override
public List findAll() throws IOException {
//加载主配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//获取sqlsessionFactory对象 产生sqlsession
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取sqlsession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
List users = sqlSession.selectList("findAll");
return users;
}
Mybatis的底层使用的是动态代理开发方式实现DAO层。
在开发中主需要编写Mapper接口,有mybatis根据接口定义创建接口的动态代理对象。代理对象的方法体和上述的实现是一样的。
mybatis动态代理实现dao层的规范:
- mapper.xml文件中的namespace与mapper接口的全限定类名相同
- mapper接口方法名和mapper.xml中定义的每个statment的id相同
- mapper接口方法的输入参数类型和mapper.xml中的定义的sql的parameterType的类型相同
- mapper接口方法的输出参数类型和mapper.xml中定义的resultType的类型相同
sql映射文件的顶级结构
- sql – 可被其它语句引用的可重用语句块。
- insert – 映射插入语句。
- update – 映射更新语句。
- delete – 映射删除语句。
- select – 映射查询语句。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
If
在根据条件查询中,如果接收到用户传递的查询条件,则根据传递的条件进行查询,否则就是查询所有
ListfindUserByUsername(String username);
where 主要解决在条件拼接时,如果条件不成立,需要单独设置过滤条件1=1 的问题
之后的语句中是否有and。不会影响sql。会自动去除第一个and
choose when otherwise
foreach
sql
select * from users
8 分页查询
PageHelper 第三方的插件 实现分页功能。
引入依赖
com.github.pagehelper pagehelper5.3.0
在mybatis的核心配置文件中配置分页插件
测试分页
@Test
public void pageHelperTest() throws IOException {
//设置分页参数 第一个表示第几页 第二个参数表示每页显示的条数
PageHelper.startPage(2,5);
List users = mapper.findAll();
System.out.println(users);
System.out.println("-------------分页相关参数--------");
PageInfo info = new PageInfo<>(users);
System.out.println("总记录数:" + info.getTotal());
System.out.println("总页数:" + info.getPages());
System.out.println("当前页:"+ info.getPageNum());
System.out.println("每页显示的记录数:"+info.getPageSize());
System.out.println("是否是第一页:" + info.isIsFirstPage());
System.out.println("是否是最后一页:" + info.isIsLastPage());
}



