JDBC问题分析:
1、数据库配置存在硬编码 (配置文件解决)
2、频繁创建释放数据库连接 (连接池解决)
3、sql语句、设置参数、获取结果集参数 硬编码 (配置文件解决)
4、手动封装返回结果集,较为繁琐 (反射、内省解决)
自定义持久层框架设计思路:
使用端:(项目)引入自定义持久层框架的jar包
提供两部分配置信息:数据库配置信息、sql配置信息:sql语句、参数类型、返回值类型
使用配置文件提供配置信息:
(1)sqlMapConfig.xml:存放数据库配置信息,存放mapper.xml的全路径
(2)mapper.xml:存放sql配置信息
自定义持久层框架本身:(工程)本质是对JDBC代码进行封装
(1)加载配置文件:根据配置文件路径,加载配置文件成字节输入流,存储在内存中
创建Resources类 方法: InputSteam getResourcesAsSteam(String path)
(2)读取配置文件,创建javaBean:(容器对象):存放对配置文件解析出来的内容
Configuration:核心配置类:存放sqlMapConfig.xml解析出来的内容
MappedStatement:映射配置类:存放mapper.xml解析出来的内容
(3)解析配置文件:dom4j
创建类:SqlSessionFactoryBuilder 方法:build(InputSteam in)
第一:使用dom4j解析配置文件,将解析出来的内容封装到容器对象中
第二:创建SqlSessionFactory对象;生产sqlSession:会话对象(工厂模式)
(4)创建SqlSessionFactory接口及实现类DefaultSqlSessionFactory
第一:openSession() :生产sqlSession
(5)创建SqlSession接口及实现类DefaultSession
定义对数据库的crud操作:selectList()、selectOne()、update()、delete()
(6)创建Executor接口及实现类SimpleExecutor
query(Configuration,MappedStatement,Object… params):执行的就是JDBC代码
优化:
自定义持久层框架中存在如下问题
1.重复加载配置文件、创建SQL SessionFactory、创建sqlSession
2.硬编码访问statementId(maaper.xml中的sql名)
解决:使用代理模式生成Dao接口的代理对象(代理对象实际上是一个proxy,无论调用接口中的任意一个方法,都会调用动态代理类的invoke方法)
Mybatis复杂映射:
一对一:实体类中包含另一个类
配置方式:
<mapper namespace="com.lagou.mapper.OrderMapper">
<resultMap id="orderMap" type="com.lagou.domain.Order">
<result column="uid" property="user.id"></result>
<result column="username" property="user.username"></result>
<result column="password" property="user.password"></result>
<result column="birthday" property="user.birthday"></result>
</resultMap>
<select id="findAll" resultMap="orderMap">
select * from orders o,user u where o.uid=u.id
</select>
</mapper>
<resultMap id="orderMap" type="com.lagou.domain.Order">
<result property="id" column="id"></result>
<result property="ordertime" column="ordertime"></result>
<result property="total" column="total"></result>
<association property="user" javaType="com.lagou.domain.User">
<result column="uid" property="id"></result>
<result column="username" property="username"></result>
<result column="password" property="password"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
一对多:实体类中包含另一个类的列表
<mapper namespace="com.lagou.mapper.UserMapper">
<resultMap id="userMap" type="com.lagou.domain.User">
<result column="id" property="id"></result>
<result column="username" property="username"></result>
<result column="password" property="password"></result>
<result column="birthday" property="birthday"></result>
<collection property="orderList" ofType="com.lagou.domain.Order">
<result column="oid" property="id"></result>
<result column="ordertime" property="ordertime"></result>
<result column="total" property="total"></result>
</collection>
</resultMap>
<select id="findAll" resultMap="userMap">
select *,o.id oid from user u left join orders o on u.id=o.uid
</select>
</mapper>
多对多:
两个类互相包含对方的列表属性,拆分为两个一对多,配置方式与一对多相同
MyBatis注解:
@Insert:实现新增 @Update:实现更新 @Delete:实现删除 @Select:实现查询
注解一对一
public interface OrderMapper {
@Select("select * from orders")
@Results({
@Result(id=true,property = "id",column = "id"),
@Result(property = "ordertime",column = "ordertime"),
@Result(property = "total",column = "total"),
@Result(property = "user",column = "uid",
javaType = User.class,
one = @One(select = "com.lagou.mapper.UserMapper.findById"))
})
List<Order> findAll();
}
public interface UserMapper {
@Select("select * from user where id=#{id}")
User findById(int id);
}
注解一对多:
public interface UserMapper {
@Select("select * from user")
@Results({
@Result(id = true,property = "id",column = "id"),
@Result(property = "username",column = "username"),
@Result(property = "password",column = "password"),
@Result(property = "birthday",column = "birthday"),
@Result(property = "orderList",column = "id",
javaType = List.class,
many = @Many(select =
"com.lagou.mapper.OrderMapper.findByUid"))
})
List<User> findAllUserAndOrder();
}
public interface OrderMapper {
@Select("select * from orders where uid=#{uid}")
List<Order> findByUid(int uid);
}
Mybatis缓存:
一级缓存以Map形式存在于SqlSession中,二级缓存以map形式存在于mapper对应的namespace中,开启二级缓存时,先查询二级缓存,再查询一级缓存。
二级缓存开启:
configration:
mapper:
二级缓存整合redis:
1.pom文件
org.mybatis.caches
mybatis-redis
1.0.0-beta2
2.配置文件
Mapper.xml
3.redis.properties
redis.host=localhost
redis.port=6379
redis.connectionTimeout=5000
redis.password=
redis.database=0
Mybatis插件:
对执行器Executor、SQL语法构建器StatementHandler、参数处理器ParameterHandler、结果集处理器ResultSetHandler四大核心对象的动态代理,并在invoke中进行增强。
自定义插件:
configration:
<plugins>
<plugin interceptor="com.lagou.plugin.MySqlPlugin">
<!--配置参数-->
<property name="name" value="Bob"/>
</plugin>
</plugins>
@Intercepts({
@Signature(type= StatementHandler.class,
method = "prepare",
args = {Connection.class,Integer.class})
})
public class MyPlugin implements Interceptor {
/*
拦截方法:只要被拦截的目标对象的目标方法被执行时,每次都会执行intercept方法
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("对方法进行了增强....");
return invocation.proceed(); //原方法执行
}
/*
主要为了把当前的拦截器生成代理存到拦截器链中
*/
@Override
public Object plugin(Object target) {
Object wrap = Plugin.wrap(target, this);
return wrap;
}
/*
获取配置文件的参数
*/
@Override
public void setProperties(Properties properties) {
System.out.println("获取到的配置文件的参数是:"+properties);
}
}
pageHelper分页插件使用:
①导入通用PageHelper坐标
com.github.pagehelper
pagehelper
3.7.5
com.github.jsqlparser
jsqlparser
0.9.1
② 在mybatis核心配置文件中配置PageHelper插件
③ 测试分页代码实现
@Test
public void pageHelperTest(){
PageHelper.startPage(1,1);
List<User> users = userMapper.selectUser();
for (User user : users) {
System.out.println(user);
}
PageInfo<User> pageInfo = new PageInfo<>(users);
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("当前页:"+pageInfo.getPageNum());
System.out.println("每页显示的条数:"+pageInfo.getPageSize());
}
Builder构建者模式
Builder模式的定义是"将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表
示。”,它属于创建类模式,一般来说,如果一个对象的构建比较复杂,超出了构造函数所能包含的范
围,就可以使用工厂模式和Builder模式,相对于工厂模式会产出一个完整的产品,Builder应用于更加
复杂的对象的构建,甚至只会构建产品的一个部分,直白来说,就是使用多个简单的对象一步一步构建
成一个复杂的对象
例子:使用构建者设计模式来生产computer
主要步骤:
1、将需要构建的目标类分成多个部件(电脑可以分为主机、显示器、键盘、音箱等部件);
2、 创建构建类;
3、 依次创建部件;
4、 将部件组装成目标对象
工厂模式
在Mybatis中比如SqlSessionFactory使用的是工厂模式,该工厂没有那么复杂的逻辑,是一个简单工厂
模式。
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于创
建型模式。
在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建
其他类的实例,被创建的实例通常都具有共同的父类
代理模式
代理模式(Proxy Pattern):给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式
的英文叫做Proxy,它是一种对象结构型模式,代理模式分为静态代理和动态代理,我们来介绍动态代
理