1. JDBC问题分析
我们来看一段JDBC的代码:
public static void main(String[] args) { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { //1. 加载数据库驱动 Class.forName("com.mysql.jdbc.Drive"); //2. 通过驱动管理类获取数据库链接 connection = DriverManager.getConnection("jdbc:mysql://hocalhost:3306/mybatis?characterEncoding=utf-8", "root","root"); //3. 定义SQL语句 ?表示占位符 String sql = "SELECT * FROM user WHERE username = ?"; //4. 获取预处理对象Statement preparedStatement = connection.prepareStatement(sql); //5. 设置参数,第一个参数为SQL语句中参数的序号(从1开始),第二个参数为设置的参数值 preparedStatement.setString(1,"tom"); //6. 向数据库发出SQL执行查询,查询出结果集 resultSet = preparedStatement.executeQuery(); //7. 遍历查询结果集 while (resultSet.next()){ int id = resultSet.getInt("id"); String userName = resultSet.getString("username"); //封装User user.setId(id); user.setUserName(userName); } System.out.println(user); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); } }
可以看到,直接使用JDBC开发是存在一些问题的,我们来分析下:
问题分析:
数据库配置信息存在硬编码问题
频繁创建、释放数据库链接
//1. 加载数据库驱动Class.forName("com.mysql.jdbc.Drive");//2. 通过驱动管理类获取数据库链接connection = DriverManager.getConnection("jdbc:mysql://hocalhost:3306/mybatis?characterEncoding=utf-8","root","root");
sql语句、设置参数、获取结果集均存在硬编码问题
//3. 定义SQL语句 ?表示占位符String sql = "SELECT * FROM user WHERE username = ?";//4. 获取预处理对象StatementpreparedStatement = connection.prepareStatement(sql);//5. 设置参数,第一个参数为SQL语句中参数的序号(从1开始),第二个参数为设置的参数值 preparedStatement.setString(1,"tom"); //6. 向数据库发出SQL执行查询,查询出结果集 resultSet = preparedStatement.executeQuery(); int id = resultSet.getInt("id"); String userName = resultSet.getString("username");
手动封装返回结果集 较为繁琐
//7. 遍历查询结果集while (resultSet.next()){ int id = resultSet.getInt("id"); String userName = resultSet.getString("username"); //封装User user.setId(id); user.setUserName(userName); } System.out.println(user);
解决思路:
写在配置文件中
连接池(c3p0、dbcp、德鲁伊...)
配置文件 (和1放一起吗? No,经常变动和不经常变动的不要放在一起)
反射、内省
下面根据这个解决思路,自己动手写一个持久层框架,写框架之前分析这个框架需要做什么
2. 自定义框架思路分析
使用端(项目):
引入自定义持久层框架的jar包
提供两部分配置信息:
数据库配置信息
SQL配置信息(SQL语句)
使用配置文件来提供这些信息:
sqlMapConfig.
mapper.
自定义持久层框架(工程):
持久层框架的本质就是对JDBC代码进行了封装
加载配置文件:根据配置文件的路径加载配置文件成字节输入流,存储内存中
创建Resources类 方法:getResourceAsStream(String path)
Q: getResourceAsStearm方法需要执行两次分别加载sqlMapConfig额和mapper吗?
A:可以但没必要,我们可以在sqlMapConfig.
创建两个javaBean:(容器对象):存放的就是配置文件解析出来的内容
Configuration:核心配置类:存放sqlMapConfig.
MappedStatement:映射配置类:存放mapper.
解析配置文件:使用dom4j
创建类:SqlSessionFactoryBuilder 方法:build(InputStream in) 这个流就是刚才存在内存中的
使用dom4j解析配置文件,将解析出来的内容封装到容器对象中
创建SqlSessionFactory对象;生产sqlSession:会话对象(工厂模式 降低耦合,根据不同需求生产不同状态的对象)
创建sqlSessionFactory接口及实现类DefaultSqlSessionFactory
openSession(); 生产sqlSession
创建SqlSession接口及实现类DefaultSession
定义对数据库的CRUD操作,例如:
selectList()
selectOne()
update()
delete()
...
创建Executor接口及实现类SimpleExecutor实现类
query(Configuration con,MappedStatement ms,Object ...param);执行JDBC代码,Object ...param具体的参数值,可变参;
3. 创建表并编写测试类
SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;-- ------------------------------ Table structure for user-- ----------------------------DROP TABLE IF EXISTS `user`;CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ------------------------------ Records of user-- ----------------------------INSERT INTO `user` VALUES (1, 'lucy');INSERT INTO `user` VALUES (2, 'tom');INSERT INTO `user` VALUES (3, 'jack');SET FOREIGN_KEY_CHECKS = 1;
1. 创建一个Maven项目—— Ipersistence_test
Q:
为什么要有namespace和id ?
A:
当一个*Mapper.中有多条sql时,无法区分具体是哪一条所以增加 id
如果有UserMapper.和ProductMapper.,假设他们的查询的id都为”selectList“,那么将无法区分具体是查询user还是查询product的。
所以增加 namespace
namespace.id 组成sql的唯一标识,也称为statementId
sqlMapConfig.