我们来看一段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. 获取预处理对象Statement preparedStatement = 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.xml :存放数据库的配置信息
mapper.xml :存放SQL配置信息
自定义持久层框架(工程):持久层框架的本质就是对JDBC代码进行了封装
加载配置文件:根据配置文件的路径加载配置文件成字节输入流,存储内存中
创建Resources类 方法:getResourceAsStream(String path)
Q: getResourceAsStearm方法需要执行两次分别加载sqlMapConfig额和mapper吗?
A:可以但没必要,我们可以在sqlMapConfig.xml中写入mapper.xml的全路径即可
创建两个javaBean:(容器对象):存放的就是配置文件解析出来的内容
Configuration:核心配置类:存放sqlMapConfig.xml解析出来的内容
MappedStatement:映射配置类:存放mapper.xml解析出来的内容
解析配置文件:使用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 2. 在resource中创建sqlMapConfig.xml 和 UserMapper.xml