《Java手写系列》-手写MyBatis框架
Posted IT老刘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Java手写系列》-手写MyBatis框架相关的知识,希望对你有一定的参考价值。
文章目录
1.前言
我们刚开始搞java的时候,貌似都知道用jdbc去连接数据库,那我们来看一下jdbc连接数据库的代码:
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 通过驱动管理类获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8",
"root", "root");
// 定义sql语句 ?标识占位符
String sql = "select * from user where id = ? aand username = ?";
// 获取预处理statement
ps = conn.prepareStatement(sql);
// 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为 设置的参数值
ps.setString(1, "riemann");
// 向数据库发出sql执行查询,查询出结果集
rs = ps.executeQuery();
// 遍历结果集
while (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
// 封装User
user.setId(id);
user.setUsername(username);
}
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放资源
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2.JDBC问题分析
- 数据库连接创建、释放频繁造成系统资源浪费,从而影响性能。
- sql语句存在硬编码,造成代码不易维护。
- 使用preparedStatement向占有位符号传参数存在硬编码问题。
- 对结果解析存在硬编码(查询列名),sql变化导致解析代码变化。
3.问题解决方案
- 数据库频繁创建连接以及释放资源:连接池
- sql语句及参数存在硬编码: 配置文件
- 手动解析封装返回结果集: 反射、内省
这也就解释了前面提的问题,为什么要有mybatis
框架的存在?这是因为为了解决JDBC
操作存在的这些问题。
好了,下面我们就来针对上面的解决方案来设计一个mybatis框架。
4.自定义框架实现
4.1.准备测试数据库
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'jackUpdate');
INSERT INTO `user` VALUES ('2', 'tom');
4.2.导入项目依赖
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<!--Lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
4.3.创建mybatis-config.xml
<configuration>
<!--数据库配置信息-->
<dataSource>
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/handwrite_mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</dataSource>
<!--存放mapper.xml的全路径-->
<mapper resource="mappers/UserMapper.xml"></mapper>
</configuration>
4.4.创建实体类User
package com.bruce.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
}
4.5.创建Dao层
package com.bruce.dao;
import com.bruce.pojo.User;
import java.util.List;
public interface UserDao {
/**
* 查询所有用户
* @return User的集合
*/
List<User> findAll();
/**
* 根据条件进行用户查询
* @return User对象
* @param user
*/
User selectOne(User user);
void insert(User user);
void update(User user);
void delete(User user);
}
4.6.编写测试类
package com.bruce.test;
import com.bruce.dao.UserDao;
import com.bruce.pojo.User;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class PersistenceTest {
UserDao userDao;
@Before
public void before() throws Exception {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
userDao = sqlSession.getMapper(UserDao.class);
}
@Test
public void testSelect() throws Exception {
// 调用
List<User> all = userDao.findAll();
System.out.println(all);
}
}
至此为止,手写MyBatis的基础环境已经有了,但是有个问题就是测试类中的sqlSession获取的问题,因为测试类中的API很明显没有,所以接下来需要手写sqlSession代码,并且在底层需要通过动态代理的方式给接口生成实现类对象!
以上是关于《Java手写系列》-手写MyBatis框架的主要内容,如果未能解决你的问题,请参考以下文章