Mybatis 学习
一、自定义持久层框架
1.1 分析
持久层。与数据交互的一层。Dao层 。
可能存在的问题:
问题 | 代码 | 解决方案 |
硬编码。对底层驱动和数据库配置信息硬编码 |
Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection("jdbc::mysql://localhost:
|
通过配置文件 |
每一次请求都开启新链接。每次建立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)
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允许拦截的方法:
- Executor
- StatementHandler
- ParameterHandler
- ResultSetHandler