2、三层架构与SSM框架
SSM框架:Spring、SpringMVC、Mybatis3个架构;三层架构:表现层(web)、业务逻辑层(service)、数据访问层(dao)。
2个补充
1、什么是框架?
它是我们软件开发中的一套解决方案,不同的框架解决的是不同的问题。
使用框架的好处:
框架封装了很多的细节,使开发者可以使用极简的方式实现功能。大大提高开发效率。
2、三层架构
表现层:是用于展示数据的
业务层:是处理业务需求
持久层:是和数据库交互的
3、持久层技术解决方案
JDBC技术:
Connection,PreparedStatement,ResultSet
Spring
Jdbc Template:Spring中对jdbc的简单封装
Apache
DBUtils:它和Spring的JdbcTemplate很像,也是对Jdbc的简单封装
以上这些都不是框架
JDBC是规范,Spring的Jdbc Template和Apache的DBUti1s都只是工具类。
4、mybatis的概述
mybatis是一个持久层框架,用java编写的。它封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程,它使用了ORM思想实现了结果集的封装。
ORM:Object Relational Mappging 对象关系映射
简单的说,就是把数据库表和实体类及实体类的属性对应起来,让我们可以操作实体类就实现操作数据库表。比如数据库中的user表,对应java中的User类。暂时我们需要做到,实体类中的属性和数据库表的字段名称保持一致。
5、mybatis环境搭建
在数据库中创建一个 lkj_mybatis 数据库,并添加user表,同时插入数据。
CREATE DATABASE lkj_mybatis; -- 创建数据库
USE lkj_mybatis; -- 使用数据库
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(32) NOT NULL COMMENT '用户名称',
`birthday` DATETIME DEFAULT NULL COMMENT '生日',
`sex` CHAR(1) DEFAULT NULL COMMENT '性别',
`address` VARCHAR(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
创建一个Maven的普通的java工程(可以不使用Maven的java骨架),在pom.xml中添加打包方式为jar。随后,导入mybatis的坐标**(注意,在Maven项目中使用mybatis是需要添加mybatis的jar包在仓库中的坐标的)**。 同时,还需要导入mysql、log4j(日志)、junit模块的坐标。
domain包下添加一个User实体类,目前,User类的属性名要与数据库user的属性名相同。dao包下创建一个UserDao,用户的持久层接口。
//UserDao
package com.lkj.dao;
import com.lkj.domain.User;
import java.util.List;
/**
* 用户的持久层接口
*/
public interface UserDao
{
/**
* 查询所有用户并放入List集合
* @return
*/
List<User> findAll();
}
在resource下创建一个xml配置文件,一般叫SqlMapConfig.xml,随后对该文件进行配置,这个文件是mybatis的主配置文件。
在resource下创建一个dao的独立的xml配置文件(也叫映射配置文件),需要注意的是,dao(持久层)的独立配置文件,必须和dao持久层接口在相同的包中。
代码如下
----SqlMapConfig.xml
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/lkj_mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/lkj/dao/UserDao.xml" />
mappers>
configuration>
------UserDao.xml
<mapper namespace="com.lkj.dao.UserDao">
<select id="findAll" resultType="com.lkj.domain.User">
select * from user;
select>
mapper>
总结:
mybatis的环境搭建
第一步:创建maven工程并导入坐标
第二步:创建实体类和dao的接口
第三步:创建Mybatis的主配置文件:SqlMapConifg.xml
第四步:创建映射配置文件:UserDao.xml
环境搭建的注意事项:
第一个:创建UserDao.xml和UserDao.java时名称是为了和我们之前的知识保持一致。在Mybatis中它把持久层的操作接口名称和映射文件也叫做:Mapper所以:IUserDao和IUserMapper是一样的;
第二个:在idea中创建目录Directory的时候,它和包Package是不一样的。包在创建时:com.itheima.dao它是三级结构目录,在目录创建时:com.itheima.dao是一级目录。我们在resource中没办法创建包,但是又要创建三级目录结构,就必须一级一级地创建Directory,如果一次性创建Directory:com.itheima.dao,只有一级目录结构!这点要注意;
第三个:mybatis的映射配置文件包结构必须和dao接口的包结构相同;
第四个:映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名;
第五个:映射配置文件的操作配置(如select),id属性的取值必须是dao接口的方法名。
当我们遵从了第三,四,五点之后,我们在开发中就无须再写dao的实现类,mybatis会帮我们完成实现类的操作。I
6、mybatis的入门案例
先将log4j的配置文件log4j.properties放入resource中。
在test.java包下,创建一个新的包com.lkj.test,在下面创建一个MybatisTest.java的类进行测试(注意,我们这里不需要再写DAO的实现类!)。
步骤:
第一步:读取配置文件
第二步:创建SqlSessionFactory工厂
第三步:创建SqlSession
第四步:创建Dao接口的代理对象
第五步:执行dao中的方法
第六步:释放资源
注意事项:
不要忘记在映射配置中告知mybatis要封装到哪个实体类中。配置的方式:指定实体类的全限定类名
代码
package com.lkj.test;
public class MybatisTest
{
/**
* 入门案例
* 注意,记住这里实现SQL操作的6个步骤!!!
* @param args
*/
public static void main(String[] args) throws IOException
{
//1.读取配置文件(Mybatis的主配置文件SqlMapConfig.xml)
/*
这里使用Mybatis的getResourceAsStream方法来读取配置文件。
读取的mybatis的主配置文件在resources目录下,不需要加其他目录,直接写“SqlMapConfig.xml”即可
*/
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
/*
SqlSessionFactory是一个接口,我们必须要创建其实现类,而Mybatis已经为我们创建了相应的实现类:SqlSessionFactoryBuilder,
我们直接使用这个实现类对象的build()方法即可创建SQLSessionFactory对象
*/
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);//注意将配置文件读取流对象放进去
//3.使用工厂生产SqlSession对象(这个对象用于为我们提供DAO的实现)
SqlSession session = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
// 我们一般不使用SqlSession的对象实现dao层的方法,而会通过dao层相应dao的代理对象来实现其方法
UserDao userDao = session.getMapper(UserDao.class);
//5.使用代理对象执行方法
List<User> list = userDao.findAll();
for (User user : list)
{
System.out.println(user);
}
//6.释放资源
session.close();//先关闭SqlSession对象
is.close();//再关闭文件读取流对象
}
}
7、mybatis的注解开发与编写dao实现类的方式
创建一个新的项目mybatis_day01_annotation(同样是普通java项目)。为了方便,先将各个mybatis_day01项目的文件都拷贝过来,同时在pom.xml文件中导入mybatis以及其他相关组件的jar的坐标。测试刚刚的测试类,发现可以使用即可。
1、dao的独立配置文件没有用,我们要通过注解来配置,我们将dao的配置文件的包:com.lkj.dao.UserDao.xml删除。但是mybatis的主配置文件不能删除!!!
2、在UserDao的方法前面加上注解,注解中写上要执行的SQL语句
@Select("select * from user")
List<User> findAll();
3、在主配置文件中,我们不需要再指定dao的独立配置文件,而是要在主配置文件中指定操作的被注解的dao(原先是在dao的配置文件UserDao.xml中的namespace属性指定要操作的dao),使用class属性指定被注解的dao全限定类名。
<mappers>
//
<mapper class="com.lkj.dao.UserDao"/>
</mappers>
总结:
现在只需要在dao接口的方法上使用@Select注解,并且指定SQL语句。同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名。这里也不需要指定最后的结果最后封装的实体类。因为最后封装的结果类型在方法中已经有定义:List<User> findAll(); 就是这里面的User。因此,我们不需要再指定结果类型。
说明:我们在实际开发中,不管使用XML还是注解配置,都是越简便越好,所以都是采用不写dao实现类的方式。但是Mybatis它是支持写dao实现类的。
创建自己测试的项目mybatis_day01_dao,同样将第一个项目的所有资源放进来,同时在dao包下添加一个impl.UserDaoImpl.java实现类。
代码如下,我们只需要修改实现类UserDaoImpl与测试类MyBatisTest的代码,其他的不变。
//实现类UserDaoImpl
package com.lkj.dao.impl;
public class UserDaoImpl implements UserDao
{
//由于是我们自己写实现类,前面使用SqlSession生成dao的代理对象这一步就不需要!
// 读取配置文件、创建SqlSessionFactory工厂、使用工厂生产SqlSession对象、使用SqlSession对象执行、释放资源
/*
我们先在UserDaoImpl中创建一个SqlSessionFactory的引用,然后在调用这个UserDaoImpl的service或者是测试类中,
创建这个UserDaoImpl的对象,并且将这个SqlSessionFactory对象传递进来,即可在UserDaoImpl使用SqlSessionFactory。
同时,我们需要在service或者是测试类中 读取配置文件、创建SqlSessionFactory工厂并创建UserDaoImpl对象,调用findAll方法完成查询。
*/
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory)
{
this.factory = factory;
}
public List<User> findAll()
{
//使用工厂生产SqlSession对象
SqlSession session = factory.openSession();
/*
使用SqlSession自带的方法执行SQL语句并返回。
注意,这里可以在selectList中自己写SQL语句,但是这样我们之前在UserDao.xml中已经配置过UserDao接口中findAll方法的SQL语句,
这里我们直接通过UserDao.xml配置来获取执行语句,我们在UserDao.xml配置中已经通过namespace="com.lkj.dao.UserDao" 指定了findAll方法作用的dao(UserDao),
我们直接写要执行的方法在UserDao接口中的全名即可:"com.lkj.dao.UserDao.findAll"
注意,如果使用的是注解开发,没有UserDao.xml,这时如果想要获取执行语句,同样通过"com.lkj.dao.UserDao.findAll",
“com.lkj.dao.UserDao.findAll”会找到UserDao类下的findAll()方法,注解方法的SQL语句定义在findAll方法上,这样实现类也可以找到SQL语句。
注意:不管使用的是dao.xml的方式还是使用注解的方式,都可以创建UserDao的实现类,关键的是selectList()方法通过 “com.lkj.dao.UserDao.findAll” 找到UserDao.xml中select标签定义的SQl语句,或者是找到UserDao.java中注解@Select中定义的SQL语句。
*/
List<User> list = session.selectList("com.lkj.dao.UserDao.findAll");
//关闭SqlSession对象
session.close();
return list;
}
}
//测试类MyBatisTest
package com.lkj.test;
public class MybatisTest
{
/**
* 入门案例
* 注意,记住这里实现SQL操作的6个步骤!!!
* @param args
*/
public static void main(String[] args) throws IOException
{
//1.读取配置文件(Mybatis的主配置文件SqlMapConfig.xml)
/*
这里使用Mybatis的getResourceAsStream方法来读取配置文件。
读取的mybatis的主配置文件在resources目录下,不需要加其他目录,直接写“SqlMapConfig.xml”即可
*/
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
/*
SqlSessionFactory是一个接口,我们必须要创建其实现类,而Mybatis已经为我们创建了相应的实现类:SqlSessionFactoryBuilder,
我们直接使用这个实现类对象的build()方法即可创建SQLSessionFactory对象
*/
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);//注意将配置文件读取流对象放进去
/**
//3.使用工厂生产SqlSession对象(这个对象用于为我们提供DAO的实现)
SqlSession session = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
// 我们一般不使用SqlSession的对象实现dao层的方法,而会通过dao层相应dao的代理对象来实现其方法
UserDao userDao = session.getMapper(UserDao.class);
*/
//这里不再需要创建dao的代理对象,因为我们有dao的实现类。直接使用工厂创建dao对象
UserDaoImpl userDao = new UserDaoImpl(factory);
//3.执行UserDaoImpl中的findAll方法
List<User> list = userDao.findAll();
for (User user : list)
{
System.out.println(user);
}
//4.释放资源
is.close();//再关闭文件读取流对象
}
}
注意,我们在开发中是不会写实现类的,这里是为了说明Mybatis想执行语句的时候,必须通过在dao的独立的配置文件UserDao.xml中,使用namespace配置语句找到要执行的dao(UserDao),使用id配置找到要执行的方法(findAll),这样就可以找到要执行的SQL语句。当然,在使用注解配置的时候,“com.lkj.dao.UserDao.findAll”也可以找到UserDao的findAll()方法上的@Select("select * from user")
注解中的sql语句!
只有指定dao、方法名与SQL语句,Mybatis才会执行。
8、mybatis入门案例中的设计模式分析
分析的就是我们第一个项目中Mybatis.test测试类的方法(主要见视频10的分析)。
1、我们在读取配置文件的时候,不管是绝对路径还是相对路径,都会面临因文件目录不存在而读取不到的问题。我们读取配置文件一般使用2个方法:
1) 使用类加载器:只能读取类路径(src)的配置文件(之前读取JDBCUtils的druid.properties配置文件就是使用这种方法,druid.properties放在类目录src的resources文件夹下,这样就可以读取到);
2) 使用ServletContext对象(代表整个项目)的getRealPath()方法,可以读取到当前项目运行位置的绝对路径(当前项目部属在哪里,它就可以读取到哪里)。
我们以后读取配置文件一般都使用这两种方法,其他的都不太靠谱。
2、创建工厂SqlSessionFactory,mybatis使用了构建者模式(视频10-4.00)。
SqlSessionFactoryBuilder的对象builder就是构建者。构建者模式的好处是,把对象繁琐的创建细节隐藏,使得使用者直接调用方法就可以拿到对象。
3、创建SqlSession对象,使用了工厂模式。
我们使用SqlSessionFactory工厂为我们生成SqlSession对象,在工厂中new SqlSession的对象,这样的优势是:解耦,降低了类之间的依赖关系。
比如我们想换一个SqlSession对象,不需要再重新new,直接在工厂中获取即可,如果直接new的话,每次都要修改代码并重新编译,重新部属项目,耦合性太强。
4、创建Dao接口实现类的对象,使用了代理模式。
优势:在不修改源码的基础上,对已有方法进行增强。
我们通过创建Dao接口实现类的代理对象,实现了不创建Dao接口的实现类也能实现功能。
我们mybatis中创建了那么多对象,其实可以更加简单,为什么要创建这么多对象?
因为创建的类越多,代码就更加灵活,我们在使用的时候选择性更多。后面我们可能就会把中间的细节全部屏蔽,只专注于功能的实现。
9、自定义Mybatis的分析-执行查询所有的分析(视频11)与创建代理对象的分析(视频12)(这部分很重要!!!)
mybatis在使用代理dao的方式实现增删改查时做什么事呢?
只有两件事:
第一:创建代理对象
第二:在代理对象中调用selectList
这部分较为复杂,见视频11,12分析。(下面的图片较为模糊,可以直接看自己的资源下的文件:D:\资源\黑马就业班2019\05-Mybatis\01-第一天\截图)
10、自定义Mybatis
自定义mybatis能通过入门案例看到类
class Resources
class SqlSessionFactoryBuilder
interface SqlSessionFactory
interface SqlSession
创建一个新的项目:mybatis_day01_design。先将各个mybatis_day01项目的文件都拷贝过来,同时在pom.xml文件中导入mybatis以及其他相关组件的jar的坐标。
随后,我们在项目pom.xml中将Mybatis的依赖坐标删除,因为我们要自定义Mybatis。同时,我们将主配置文件与UserDao的配置文件UserDao.xml的mybatis约束全部删除。(注意不要将第一行xml文件的定义也删除!)
下面就是要创建Mybatis相关的类与接口
1、创建一个Resources类。
在这个类中创建一个getResourceAsStream(String filePath)方法,根据类加载器读取配置文件。(配置文件)
2、创建SqlSessionFactoryBuilder类、SqlSessionFactory接口、SqlSession接口。(3个类与接口的方法见代码,不再赘述)
下面的代码补全,见视频13-视频
3、几个类的说明:
XMLConfigBuilder:用于解析配置文件(从配置文件流中读取配置的连接信息与映射信息并封装到Configuration对象中);
Configuration:自定义mybatis的配置类(用于封装连接信息及映射信息(sql语句与结果封装的实体类的全限定类名),连接信息与映射信息的涵义见上图);
Mapper:用于封装执行的SQL语句和结果类型的全限定类名;
DefaultSqlSessionFactory:SqlSessionFactory接口的实现类;
DefaultSqlSession:SqlSession接口的实现类;
Executor:负责执行SQL语句,并且封装结果集;
DataSourceUtil:用于创建数据源的工具类(这里用于获取数据库的连接);
MapperProxy:用于代理Proxy.newProxyInstance过程中,实现InvocationHandler接口,并对findAll方法进行增强。
流程说明:我们使用Resource的getResourceAsStream获取主配置文件的读取流,随后,XMLConfigBuilder工具类的loadConfiguration方法,使用Resource提供的读取流,将主配置文件所映射的dao的独立配置文件的信息——执行的SQL语句,结果封装的实体类的全限定类型(这两个用Mapper封装,映射信息,Map中Mapper的key是com.lkj.dao.UserDao.findAll)与 数据库连接信息 ,封装到自定义mybatis的配置类Configuration中。
随后,将这些信息Configuration交给构建者SqlSessionFactoryBuilder,构建者使用build方法,创建了一个工厂接口SqlSessionFactory的对象DefaultSqlSessionFactory,工厂对象使用openSession方法,创建了一个SqlSession接口的对象DefaultSqlSession。
接下来,我们在DefaultSqlSession中使用getMapper方法来创建代理对象,并增强原来UserDao对象的findAll方法,使得代理对象可以调用findAll方法执行查询所有的操作。(具体细节见代码)
其实最后那么多操作总结起来只有2件事:创建代理对象,执行查询所有。
使用注解实现自定义Mybatis,见视频17。(测试的时候将UserDao.xml删除)