框架概述
1.1什么是框架
框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交与的方法;
另一种定义认为,框架是可被应用开发者定制的应用骨架。
前者是从应用方面而后者是从目的方面给出的定义。简而言之,框架其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。
1.2框架要解决的问题
框架要解决的最重要的一个问题是技术整合的问题,在J2EE 的 架中,有着各种各样的技术,不同的软件企业需要从J2EE 中选择不同的技术,这就使得软件企业最终的应用依赖于这些技术,技术自身的复杂性和技术的风险性将会直接对应用造成冲击。而应用是软件企业的核心,是竞争力的关键所在,因此应该将应用自身的设计和具体的 实现技术解耦。
这样,软件企业的研发将集中在应用的设计上,而不是具体的技术实现,技术实现是应用的底层支撑,它不应该直接对应用产生影响。
框架一般处在低层应用平台(如J2EE)和高层业务逻辑之间的中间层。
1.3软件开发的分层重要性
框架的重要性在于它实现了部分功能,并且能够很好的将低层应用平台和高层业务逻辑进行了缓和。为了实现 软件工程中的“高内聚、低合"。把问题划分开来各个解决,易于控制,易于延展,易于分配资源。我们常见的 MVC 软件设计思想就是很好的分层思想。
![](https://img-blog.csdnimg.cn/img_convert/e4bfc2578ec4d79d8563142d104ea87a.jpeg)
1.4分层开发下的常见框架
常见的JavaEE开发框架:
解决数据的持久化问题的框架
MyBatis
MyBatis本是apache的一个开源项目Batis,2010年这个项目由apache software foundation 迁移d到了googe code,并且改名为MyBatis。2013年11月迁移到Github。
iBATIS一词来源于"intemer和“abatis的组合,是一个基于Java的持久层框架。BATIS提供的持久层框架包括SQL Maps和DataAccess Objects (DAOs)
作为持久层的框架,还有一个封装程度更高的架就是Hibernate,但这个框架因为各种原因目前在国内的流行程度下降大多,现在公司开发也越来越少使用。目前使用SpringData来实现数据持久化也是一种趋势。
![](https://img-blog.csdnimg.cn/img_convert/96a1e8aca7c666b71feba686f8dceda8.png)
2. 解决WEB层问题的MVC框架
Spring MVC
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面,Spring 摇架提供了构建Web 应用程序的全功能MVC模块。使用 Spring 可插入的MVC架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的SpringMVC框架或集成其他MVC开发框架,如Struts仰扁挫蹦傍靶哀现在一般不用),Struts2等。
![](https://img-blog.csdnimg.cn/img_convert/f2f702e7af740ee5a5a0755835b66ab0.png)
3. 解决技术整合问题的框架
spring框架
Spnng挺架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松合性角度而言,绝大部分Java应用都可以从Spring中受益。
目的:解决企业应用开发的复杂性
功能:使用基本的JavaBean代智EJB,并提供了更多的企业应用功能
范围:任何Java应用
Spring是一个轻量级控制反转(loC)和面向切面(AOP)的容器框架。
2.MyBatis简介
2.1什么是MyBatis?
MyBatis是一个开源轻量级的数据持久化框架,是JDBC和Hibernate的替代方案。
MyBatis 前身为IBatis,2002 年由 Clinton Begin 发布。2010 年从Apache 移到 Google并改名为 MyBatis,2013 年又迁移到了Github。
mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement 等繁杂的过程。
mybatis通过xml或注解的方式将要执行的各种statement 配置起来并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句最后由mybatis框架执行sql并将结果映射为iava对象并返回。
采用ORM思想解决了实体和数据库映射的问题,对jdbc进行了封装,屏蔽了jdbcapi底层访问细节,使我们不用与jdbcapi打交道,就可以完成对数据库的持久化操作。
MyBatis支持定制化SQL、存储过程以及高级映射,可以在实体类和SQL语句之间建立映射关系,是一种半自动化的ORM实现。
MyBatis 的中文官网:https://mybatis.org/mybatis-3/zh/index.html
2.2为什么要使用MyBatis?
MvBatis主要的目的就是简化]DBC操作,并且满足高并发和高响应的要求.
回顾一下DBC代码:
public class GoodsDao {
private String jdbcdriver="com.mysql.cj.jdbc.Driver";
private String jdbcurl="jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC";
private String jdbcuser="root";
private String jdbcpassword="root";
private Connection con=null;
private PreparedStatement pstm=null;
private ResultSet rs=null;
private int row=0;
public Goods FindById(int gid){
Goods goods=new Goods();
try {
//1.加载驱动
Class.forName(jdbcdriver);
//2.获取数据库连接
con=DriverManager.getConnection(jdbcurl,jdbcuser,jdbcpassword);
//3.编写sql语句
String sql="select * from t_goods where gid=?";
//4.预处理对象
pstm=con.prepareStatement(sql);
//传参
pstm.setObject(1,gid);
//5.执行sql语句
rs=pstm.executeQuery();
if (rs.next()){
//把当前数据行中的数据取出来,存储到Goods对象中
goods.setGid(rs.getInt("gid"));
goods.setGname(rs.getString("gname"));
goods.setPrice(rs.getDouble("price"));
goods.setMark(rs.getString("mark"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (pstm!=null){
pstm.close();
}
if (con!=null){
con.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return goods;
}
}
分析以上JDBC存在的问题:
数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题.
sql 语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
使用preparedStatement向占有位符号传参数存在硬编码,因为sql语的where条件不一定可能多也可能少,修改sql还要修改代码,系统不易维护。
对结果集解析存在硬编码(查询列名),sl 变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。
再次回顾mybatis特点:
mybatis 内部封装了jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载动、创建连接、创建 statement等繁杂的过程。
mybatis 通过 ml或注解的方式将要执行的各种statement 配置起来,并通过 ava对象和statement 中sal 的动态参数进行射生成最终执行的sql语句,最后由mybatis框架执行sgl并将结果映射为java对象并返回。
采用ORM 思想解决了实体和数据库映射的问题,对 dbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作。
3.MyBatis的入门案例
下面我们来用一个入门的案例,了解一下MyBatis的基本操作步骤和使用方法。
查询、增加、删除案例
3.1创建测试的数据库
-- 判断存在即删除数据库
drop database if exists mydb;
-- 创建数据库
create database mydb;
-- 使用数据库
use mydb;
drop table if exists t_user;
-- 创建表
create table t_user(
uid int primary key auto_increment,
username varchar(20),
password varchar(20),
phone varchar(11),
address varchar(50)
);
insert into t_user(username,password,phone,address) values('张三','666','18965423548','南阳');
insert into t_user(username,password,phone,address) values('李四','333','18754263548','许昌');
insert into t_user(username,password,phone,address) values('小美','123','18565234759','信阳');
select * from t_user where username=? and password=?;
select * from t_user;
3.2创建一个Java项目并导入mybatis框架的jar包
在项目中创建一个lib文件夹放入mybatis框架的jar包,并导入项目中。
![](https://img-blog.csdnimg.cn/img_convert/f000d7ace2aa577861e7b75e75d48e39.png)
3.3创建跟表对应的实体类。
在src中创建com.chen.bean包,然后创建User实体类。
package com.zhao.bean;
public class User {
private Integer uid;
private String username;
private String password;
private String phone;
private String address;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
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;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", password='" + password + '\'' +
", phone='" + phone + '\'' +
", address='" + address + '\'' +
'}';
}
}
3.4创建针对表操作的接口类。
在src中创建com.chen.dao包,然后创建UserDao的接口,然后在接口中定义针对数据库的增删
改查等操作。
package com.zhao.dao;
import com.zhao.bean.User;
import java.util.List;
public interface UserDao {
/**
* 查询所有用户信息
*/
List<User> selectAll();
int add(User user);
int delete(int uid);
}
3.5在接口的包中创建对应的mapper映射配置文件。
在dao接口的同目录下创建跟接口名字一样的配置文件。
<?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">
<!--namespace是映射的dao接口-->
<mapper namespace="com.zhao.dao.UserDao">
<!--通过select标签进行查询
id:映射接口的方法名
parameterType:指定参数的类型(如果集合类型只需指定集合元素的类型即可)
resultType:指定返回的类型-->
<select id="selectAll" resultType="com.zhao.bean.User">
select * from t_user;
</select>
<insert id="add" parameterType="com.zhao.bean.User">
insert into t_user(username,password,phone,address) values(#{username},#{password},#{phone},#{address});
</insert>
</mapper>
3.6在src目录中创建mybatis框架的核心配置文件。
在src中创建一个文件,命名为SqlMapConfig.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:指定配置的环境信息的ID,表示默认连接该环境
-->
<environments default="mysql">
<environment id="mysql">
<!-- 配置事务的处理方式:模式使用JDBC的事务处理-->
<transactionManager type="jdbc"></transactionManager>
<!-- 数据源的默认type设置pooled,表示使用连接池-->
<dataSource type="pooled">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
<environment id="oracle">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<!--mapper配置文件-->
<mappers>
<mapper class="com.zhao.dao.UserDao"/>
</mappers>
</configuration>
3.7在测试类中进行测试
使用mybatis框架需要按照框架的步骤进行。
package com.zhao.test;
import com.zhao.bean.User;
import com.zhao.dao.UserDao;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserTest {
//1.加载核心配置文件的字节输入流
InputStream stream = null;
//2.创建SalSessionFactory的构建对象--框架使用的是构建者模式
SqlSessionFactoryBuilder builder = null;
//3.通过构建对象加载配置文件的输入流获取SqlSessionFactory
SqlSessionFactory factory = null;
//4.通过工厂对象获取SqlSession对象--执行jabc的
SqlSession sqlSession = null;
//5.通过SqlSession对象获取接口对应的代理对象
UserDao userDao = null;
@Before
public void init() throws IOException {
//1.加载核心配置文件的字节输入流
stream = Resources.getResourceAsStream("mybatis.xml");
//2.创建SalSessionFactory的构建对象--框架使用的是构建者模式
builder = new SqlSessionFactoryBuilder();
//3.通过构建对象加载配置文件的输入流获取SqlSessionFactory
factory = builder.build(stream);
//4.通过工厂对象获取SqlSession对象--执行jabc的
sqlSession = factory.openSession();
//5.通过SqlSession对象获取接口对应的代理对象
userDao = sqlSession.getMapper(UserDao.class);
}
@After
public void distroy() throws IOException {
sqlSession.commit();
sqlSession.close();
stream.close();
}
}
查询:
@Test
public void testSelectAll() throws IOException {
//6.通过代理对象执行查询方法
List<User> userList = userDao.selectAll();
//7.遍历集合
for (User user : userList) {
System.out.println(user);
}
}
查询运行结果如下:
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
User{uid=1, username='张三', password='666', phone='18965423548', address='南阳'}
User{uid=2, username='李四', password='333', phone='18754263548', address='许昌'}
User{uid=3, username='小美', password='123', phone='18565234759', address='信阳'}
User{uid=4, username='mybatis', password='333', phone='111', address='来来来'}
User{uid=5, username='mybatis', password='333', phone='111', address='来来来'}
Process finished with exit code 0
增加
@Test
public void testAdd() throws IOException {
//定义user对象,封装数据
User user = new User();
user.setUsername("mybatis");
user.setPassword("333");
user.setPhone("111");
user.setAddress("来来来");
int n = userDao.add(user);
if (n > 0) {
System.out.println("success");
} else {
System.out.println("error");
}
}
增加运行结果如下:
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
success
Process finished with exit code 0
数据库添加成功:
![](https://img-blog.csdnimg.cn/img_convert/63a6a705cb3a83896de3066d5a670f62.png)
删除
@Test
public void testDelete() throws IOException {
int n = userDao.delete(4);
if (n > 0) {
System.out.println("删除成功");
}
}
删除运行结果如下:
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
删除成功
Process finished with exit code 0
数据库删除成功:
![](https://img-blog.csdnimg.cn/img_convert/09338349e370f0179750292d2d3ad783.png)
单查:
在接口中:
//单查
User selectByuid(int uid);
在mapper映射中:
<select id="selectByuid" parameterType="int" resultType="com.zhao.bean.User">
select * from t_user where uid=#{uid};
</select>
在test测试类中:
//单查
@Test
public void testselectByUid(){
User user=userDao.selectByuid(1);
System.out.println(user);
}
单查运行结果如下:
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
User{uid=1, username='张三', password='666', phone='18965423548', address='南阳'}
Process finished with exit code 0
修改:
在接口中:
//修改
int update(User user);
在mapper映射中:
<update id="update" parameterType="com.zhao.bean.User">
update t_user set username=#{username},password=#{password},phone=#{phone},address=#{address} where uid=#{uid};
</update>
在test测试类中:
@Test
//修改
public void update(){
//1.数据回显
User olduser = userDao.selectByuid(3);
System.out.println("修改前:"+olduser);
//2.根据需要修改字段值
olduser.setUsername("lisa");
olduser.setAddress("泰国");
//3.执行数据库更新
userDao.update(olduser);
//4.再次查询
User newUser=userDao.selectByuid(3);
System.out.println("修改后:"+newUser);
}
修改运行结果如下:
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
修改前:User{uid=3, username='lisa', password='123', phone='18565234759', address='泰国'}
修改后:User{uid=3, username='lisa', password='123', phone='18565234759', address='泰国'}
Process finished with exit code 0
模糊
在接口中:
//模糊查询
List<User> selectLike(String username);
在mapper映射中:
<select id="selectLike" resultType="com.zhao.bean.User">
select * from t_user where username like concat ("%",#{username},"%");
</select>
在test测试类中:
@Test
//模糊查询2
public void testSelectLike(){
String username="李";
List<User> userList = userDao.selectLike(username);
for (User user:userList) {
System.out.println(user);
}
}
模糊查询运行结果如下:
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
User{uid=2, username='李四', password='333', phone='18754263548', address='许昌'}
Process finished with exit code 0
4.mybatis核心对象
从上一章的案例中我们可以发现Mybatis一些核心要素:
核心接口和类
Mybatis核心配置文件(SqlMapConfig.xml)
SQL映射文件(xxmapper.xml)
下面首先介绍Mybatis的核心接口和类,如下所示。
![](https://img-blog.csdnimg.cn/img_convert/8273e37c7da2803c87e36c65d0a31cbe.png)
每个Mybatis应用程序都以一个SqlSessionFactory对象的实例为核心。
首先获取 SqlSessionFactoryBuilder 对象,可以根据XML配置文件或者Configuration 类的实例构建该对象。
然后获取SqlSessionFactory对象,该对象实例可以通过SqlSessionFactoryBuilder 对象来获取。
有了SalessionFactory对象之后,就可以进而获取 SqSession 实例。alSession 对象中完全包含以数据库为背景的所有执行SQL操作的方法,用该实例可以直接执行已映射的SOL语句。
4.1SqlSessionFactoryBuilder
SqlSessiqnFactoryBuilder 会根据配置信息或者代码生成SqlSessionFactory,并且提供了多个build0)方法重载。
![](https://img-blog.csdnimg.cn/img_convert/0f499ef39f5e8ecb325a257cc954771e.png)
配置信息可以以三种形式提供给 SqlSessionFactorvBuilder的 build0方法,分别是 nputStream(字节流)Reader(字符流)Configuration (类)。
由于字节流和字符流都属于读取配置文件的方式所以就很容易想到构建一个SqlSessionFactory 有两种方式即:读取XML配置文件和编写代码。
一般习惯为采取XML配置文件的方式来构造SqlSessionFactory,这样一方面可以避免硬编码另一方面方便日后配置人员修改,避免重复编译代码。
SqiSessionFactoryBuilder的生命周期和作用域
SalSessionFactorvBuilder的最大特点就是用过即丢创建qlSessionFactory对象之后,这个类就不存在了,因此SqlSessionFactoryBuilder的最佳范围就是存在于方法体内,也就是局部变量。
4.2SqlSessionFactory
SqlSessionFactory是工厂接口而不是现实类,他的任务就是创建SqlSession,所有的 MyBatis 应用都以 SqlSessionFactory 实例为中心,SqlSessionFactory 的实例可以通过 SqSessionFactoryBuilder对象来获取。有了它以后就可以通过 SqlSession 提供的openSession()方法来获取SqlSession实例。
![](https://img-blog.csdnimg.cn/img_convert/01b7584e9678d48fc9c4102f575b45cc.png)
SqlSessionFactory的生命周期和作用域
SqISessionFactory对象一旦创建,就会在整个应用程序过程中始终存在。没有理由去销毁或再创建它,并且在应用程序运行中也不建议多次创建 SqlSessionFactory。因此 SqlSessionFactory 的最佳作用域是 Application,即随着应用程序的生命周期一直存在。这种存在于整个应用运行期间,并且只存在一个对象实例”的模式就是所谓的单例模式。
4.3SqlSession
SqlSession 是用于执行持久化操作的对象,类似于]DBC 中的onnetion。它提供了面向数据库执行 SQL命令所需的所有方法,可以通过SqlSession实例直接运行已映射的SQL语句
![](https://img-blog.csdnimg.cn/img_convert/efcc70b060e94b236809f8462fb1d9b1.png)
SqlSession的用途主要有两种。
获取映射器,让映射器通过命名空间和方法名称找到对应的SQL,发送给数据库执行后返回结果
直接通过命名信息去执行SQL返回结果,这是IBatis版本留下的方式。在sqlSession层我们可以通过
update、insert、select、delete等方法,带上SQL的id来操作XML中配置好的SQL,从而完成我的工作;与此同时它也支持事物,通过commit、rollback方法提交或者回滚事务。
Session获取映射器,然后映射器去发送sql
//获取映射器
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Role role = roleMapper.getRole(1L);//执行方法
Session直接发送sql执行并返回结果
Role role = sqlSession.selectOne("com.learn.chapter2.mapper.RoleMapper.getRole",1L);
还需查询列表的selectList等方法。
两者区别与用途
sqlSession.selectOne是功能性代码,长长的字符串比较晦涩难懂,不包含业务逻辑的含义,不符合面向对象的规范。而对于roleMapper这样的才是符合面向对象规范的编程,也更符合业务的逻辑。
使用Mapper方式,IDE可以检查Java预发,避免不必要的错误。
在实际开发中,一般都采用面向接口编程,此时是没有dao层实现类的,所以sqlSession.selectOne也不适用。