剖析JDBC操作问题

问题总结

  1. 数据库连贯创立、开释频繁造成系统资源节约,从而影响零碎性能。
  2. Sql语句在代码中硬编码,造成代码不易保护,理论利用中sql变动的可能较大,sql变动须要扭转 java代码。
  3. 应用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不肯定,可能 多也可能少,批改sql还要批改代码,零碎不易保护。
  4. 对后果集解析存在硬编码(查问列名),sql变动导致解析代码变动,零碎不易保护,如果能将数据 库 记录封装成pojo对象解析比拟不便

解决方案

  1. 应用数据库连接池初始化连贯资源
  2. 将数据库连贯配置、sql语句抽取到xml配置文件中, 使其满足开闭准则
  3. 应用反射、内省等底层技术,主动将实体与表进行属性与字段的主动映射

自定义框架设计思路

架构设计图

设计思路

应用端(提供配置)

  1. 应用sqlMapperConfig.xml提供全局配置信息(数据源等)
  2. 应用Mapper.xml提供sql语句文件信息
  3. 提供SqlSession接口类实现select、insert、update、delete操作

框架端(JDBC封装)

  1. 读取配置文件

    • 读取sqlMapperconfig.xml
    • 读取Mapper.xml
  2. 解析配置文件

    • 解析文件生成Configuration、MapperStatement对象
  3. 执行JDBC流程

自定义框架实现

应用端

创立配置文件

sqlMapperConfig.xml(全局配置文件,包含数据源配置,mapper门路等)
<?xml version="1.0" encoding="utf-8" ?><configuration><!--数据源配置--><datasource><property name="driverClass" value="com.mysql.cj.jdbc.Driver"/><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/><property name="username" value="root"/><property name="password" value=""/></datasource><!--引入mapper.xml文件门路--><mapper resource="mapper/userMapper.xml"/></configuration>
mapper.xml(namespace命名空间、SQL语句配置等)
<?xml version="1.0" encoding="utf-8" ?><mapper namespace="com.gigabytc.dao.UserDao"><select id="findAll" resultType="com.gigabytc.entity.User" >select * from user</select><select id="findByCondition" resultType="com.gigabytc.entity.User" parameterType="com.gigabytc.entity.User">select * from user where id = #{id} and username = #{username}</select><insert id="addUser" parameterType="com.gigabytc.entity.User" resultType="int">insert into user values(#{id}, #{username}, #{password}, #{birthday})</insert><update id="updateUser" parameterType="com.gigabytc.entity.User" resultType="int" >update user SET username = #{username}, password=#{password}, birthday=#{birthday} WHERE id = #{id}</update><delete id="deleteUser" parameterType="com.gigabytc.entity.User" resultType="int" >delete from user where id=#{id}</delete></mapper>
应用sqlSession操作接口(读取配置文件构建SqlSession数据库操作)
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapperConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);sqlSession = sqlSessionFactory.openSession();List<User> list = sqlSession.selectList("user.findAll");

框架端

解析配置文件

Configuration(全局配置)
@Datapublic class Configuration {/**- 数据源*/private DataSource dataSource;/**- SQL statement汇合*/private Map<String, MapperStatement> mapperStatementMap = new HashMap<>();}
MapperStatement(SQL语句配置)
@Datapublic class MapperStatement {/**    statement-id标识(namespace+id)*/private String id;/**- 参数类型*/private String parameterType;/**- 返回类型*/private String resultType;/**- sql语句*/private String sql;/**- sql类型*/private SqlType sqlType;}
XmlConfigBuilder(全局配置解析)
public class XMLConfigBuilder {public Configuration parseConfiguration(InputStream inputStream) throws DocumentException, PropertyVetoException {Configuration configuration = new Configuration();//解析数据源配置Document document = new SAXReader().read(inputStream);Element rootElement = document.getRootElement();List<Element> list = rootElement.selectNodes("//datasource/property");Properties properties = new Properties();for (Element element : list) {String name = element.attributeValue("name");String value = element.attributeValue("value");properties.setProperty(name,value);}//构建连接池ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));comboPooledDataSource.setUser(properties.getProperty("username"));comboPooledDataSource.setPassword(properties.getProperty("password"));configuration.setDataSource(comboPooledDataSource);//读取mapper.xml文件门路,解析mapper.xmlList<Element> mapperList = rootElement.selectNodes("//mapper");for (Element element : mapperList) {String resource = element.attributeValue("resource");XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);xmlMapperBuilder.parseMapper(Resources.getResourceAsStream(resource));}return configuration;}}
XmlMapperStatementBuilder(SQL语句解析)
public class XMLMapperBuilder {private Configuration configuration;public XMLMapperBuilder(Configuration configuration) {this.configuration = configuration;}public void parseMapper(InputStream inputStream) throws DocumentException {//解析SQL statement并封装到汇合Document document = new SAXReader().read(inputStream);Element rootElement = document.getRootElement();//解析sql语句封装MapperStatementbuildStatement(rootElement, new String[]{"select", "update", "insert", "delete"});}private void parseStatement(String namespace, Element element) {String id = element.attributeValue("id");String parameterType = element.attributeValue("parameterType");String resultType = element.attributeValue("resultType");String sql = element.getTextTrim();String elementName = element.getName();SqlType sqlType = SqlType.valueOf(elementName.toUpperCase());MapperStatement mapperStatement = new MapperStatement();mapperStatement.setId(id);mapperStatement.setParameterType(parameterType);mapperStatement.setResultType(resultType);mapperStatement.setSql(sql);mapperStatement.setSqlType(sqlType);String statementId = namespace + "." + id;configuration.getMapperStatementMap().put(statementId, mapperStatement);}private void buildStatement(Element rootElement, String[] nodes) {String namespace = rootElement.attributeValue("namespace");for (String node : nodes) {List<Element> list = rootElement.selectNodes("//" + node);for (Element element : list) {parseStatement(namespace, element);}}}}

SqlSession相干接口实现

SqlSessionFactoryBuilder
public class SqlSessionFactoryBuilder {public SqlSessionFactory build(InputStream inputStream) throws PropertyVetoException, DocumentException {XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder();Configuration configuration = xmlConfigBuilder.parseConfiguration(inputStream);return new DefaultSqlSessionFactory(configuration);}}
DefaultSqlSessionFactory
public class DefaultSqlSessionFactory implements SqlSessionFactory{private final Configuration configuration;public DefaultSqlSessionFactory(Configuration configuration) {this.configuration = configuration;}@Overridepublic SqlSession openSession() {return new DefaultSqlSession(configuration);}}
DefaultSqlSession
public class DefaultSqlSession implements SqlSession{public DefaultSqlSession(Configuration configuration) {this.configuration = configuration;}private Configuration configuration;@Overridepublic <E> List<E> selectList(String statementId, Object... params) throws Exception {Executor selectExecutor = new SelectExecutor();MapperStatement mapperStatement = configuration.getMapperStatementMap().get(statementId);return selectExecutor.query(configuration, mapperStatement, params);}@Overridepublic <T> T selectOne(String statementId, Object... params) throws Exception {List<Object> objects = selectList(statementId, params);if (objects.size() == 1) {return (T) objects.get(0);}else {throw new RuntimeException("查问后果过多或不存在");}}@Overridepublic int insert(String statementId, Object... params) throws Exception {return this.update(statementId,params);}@Overridepublic int update(String statementId, Object... params) throws Exception {Executor updateExecutor = new UpdateExecutor();MapperStatement mapperStatement = configuration.getMapperStatementMap().get(statementId);return updateExecutor.update(configuration,mapperStatement,params);}@Overridepublic int delete(String statementId, Object... params) throws Exception {return this.update(statementId,params);}@Overridepublic <T> T getMapper(Class<?> c) {Object o = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{c}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Class<?> declaringClass = method.getDeclaringClass();String statementId = declaringClass.getName() + "." + method.getName();MapperStatement mapperStatement = configuration.getMapperStatementMap().get(statementId);SqlType sqlType = mapperStatement.getSqlType();switch (sqlType) {case SELECT:Type genericReturnType = method.getGenericReturnType();// 判断是否进行了 泛型类型参数化if(genericReturnType instanceof ParameterizedType){return selectList(statementId, args);}return selectOne(statementId,args);case INSERT:return insert(statementId,args);case UPDATE:return update(statementId,args);case DELETE:return delete(statementId,args);default :break;}return null;}});return (T) o;}}

参考代码

lov3r/lagou_mybatis

本文由博客一文多发平台 OpenWrite 公布!