Mybatis 学习

一、自定义持久层框架

1.1 分析

持久层。与数据交互的一层。Dao层 。

可能存在的问题:

问题 代码 解决方案
硬编码。对底层驱动和数据库配置信息硬编码
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc::mysql://localhost:
3306/mybatis?characterEncoding=utf-8
", "root", "root");

 

通过配置文件
每一次请求都开启新链接。每次建立TCP链接,影响性能。频繁创建、释放链接 同上

通过连接池

sql语句、设置参数存在硬编码
String sql = "select * from user where username = ?";

 

配置文件(不建议和不经常改变的内容配置文件放在一起)
手动封装返回结果集
int id = resultSet.getInt("id");
                String username = resultSet.getString("username");

 

使用反射、内省

 

1.2 自定义持久层框架

使用端:引入自定义持久层框架的jar包

使用配置信息:数据库配置、SQL配置。使用配置文件

1、sqlMapConfig.xml (存放数据库配置信息, 存放mapper.xml 的全路径)

2、mapper.xml (存放sql配置信息)

自定义持久层框架本身 (工程,本质就是对JDBC封装)

1、加载配置文件,创建Resources类,有一个方法,getResourceAsStream.

2、创建两个javaBean:存放的就是对配置文件解析出来的内容。

Configuration, 核心配置列。存放sqlMapConfig.xml 解析出来的内容

MappedStatement:映射配置类、存放mapper.xml

3、解析配置文件:dom4j

创建类:SqlSessionFactoryBuilder 方法:build(inputStream)

  • 使用dom4j,将解析出来的内容封装到容器中
  • 创建sqlSessionFactory对象;生产sqlSession(会话对象,工厂模式)

4、创建sqlSessionFactory 接口以及实现类DefaultSqlSessionFactory,生产sqlSesion

5、创建sqlSession接口 以及实现类DefaultSession,定义数据库的crud操作:selectList(),selectOne(), update(), 

6、创建Executor 接口实现类 SimpleExecutor,query(Configuration, MappedStatement, Object ...params), 就是JDBC代码

 

 1.12

把sql读出来的数据写入 object

PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, returnClass);
Method writeMethod = propertyDescriptor.getWriteMethod();
writeMethod.invoke(o, value);

 

连接池

 ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
 comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
 comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
 comboPooledDataSource.setUser(properties.getProperty("user"));
 comboPooledDataSource.setPassword(properties.getProperty("password"));

 

执行sql

Connection connection = configuration.getDataSource().getConnection();
String sql = mappedStatement.getSql();
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();

 

1.15 动态代理

不修改原始对象的情况下,通过代理对象在方法调用前后插入额外的逻辑。通过动态代理创建的接口不管执行什么都会走到invoke

public <E> E getMapper(Class<?> mapperClass){
        Object proxyInstance =  Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //param 1
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String stateId = className + "." + methodName;

                // param2 List<User> all = userDao.findByCondition(user); args
                Type genericReturnType = method.getGenericReturnType();

                if(genericReturnType instanceof ParameterizedType) {
                    List<Object> objects = selectAll(stateId, args);
                }

                return slectOne(stateId, args);
            }
        });

        return (E) proxyInstance;
    }

 

 可以避免查询时候 写重复代码

 

二、Mybatis高级应用

2.1

  • ORM 表示对象-关系映射。实体类与数据库对应
  • 半自动
  • 轻量级
  • sql编译再配置文件中
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<configuration>
    <environments default="development">
        <environment id="development">
            <!--TO JDBC-->
            <transactionManager type="JDBC"></transactionManager>
            <!--TO user connection pool-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql:///zdy_mybatis"></property>
                <property name="userName" value="root"></property>
                <property name="password" value="root"></property>
            </dataSource>
        </environment>
    </environments>
    
    <!--存mapper.xml全路径-->
    <mapper resource="UserMapper.xml"></mapper>
</configuration>

 

 

 2.15 使用注解开发

@Insert
@Insert("insert into user values(#{id}, #{username})")
void addUser(User user);
@Update
@Update("update user set username = #{username} where id = #{id}")
void updateUser(User user);
@Delet
@Delete("delete from user where id = #{id}")
void delete(User user);
@Select
@Select("select * from user")
List<User> selectUser();

 

2.19 缓存概念回顾

  • mybatis提供了对缓存的支持,分为一级缓存和二级缓存

 

一级缓存底层是hashmap。sqlSession是一级缓存,互不影响

二级缓存夸sqlSession,Mapper级别,namespace级别。sqlSession共享二级缓存。可以理解二级缓存为配置文件。

  存的内容 具体内容 其他 何时插入值 默认开启
一级缓存

map,

key:statementid,params,boundSql,rowBounds

value: 对象

做了增删改操作,并进行了提交,则刷新一级缓存 每次查询时候,如果没有key,则put一次,如果有直接返回
二级缓存 PerpetualCache。底层是HashMap 二级缓存的是数据,并不是对象

把所有内容存入二级缓存,可以再不同的sqlSession使用。pojo需要实现序列化接口,

因为有的缓存在内存,有的在磁盘

每一次增删改需要 刷新缓存,否则会出现脏读,

否,需要手动配置,

或者使用注解

 

 

2.23 mybatis使用redis实现二级缓存

单服务器,mybaits自带二级缓存没问题,如果是分布式环境,二级缓存不好用。

使用分布式缓存,Redis、Memcached、Ehcache

@CacheNamespace(implementation = RedisCache.class)

基于RedisCache类

 

2.25 mybatis插件

Mybatis允许拦截的方法:

  1. Executor
  2. StatementHandler
  3. ParameterHandler
  4. ResultSetHandler
posted @ 2024-02-04 12:37  ylxn  阅读(4)  评论(0编辑  收藏  举报