剖析JDBC操作问题
问题总结
- 数据库连贯创立、开释频繁造成系统资源节约,从而影响零碎性能。
- Sql语句在代码中硬编码,造成代码不易保护,理论利用中sql变动的可能较大,sql变动须要扭转 java代码。
- 应用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不肯定,可能 多也可能少,批改sql还要批改代码,零碎不易保护。
- 对后果集解析存在硬编码(查问列名),sql变动导致解析代码变动,零碎不易保护,如果能将数据 库 记录封装成pojo对象解析比拟不便
解决方案
- 应用数据库连接池初始化连贯资源
- 将数据库连贯配置、sql语句抽取到xml配置文件中, 使其满足开闭准则
- 应用反射、内省等底层技术,主动将实体与表进行属性与字段的主动映射
自定义框架设计思路
架构设计图
设计思路
应用端(提供配置)
- 应用sqlMapperConfig.xml提供全局配置信息(数据源等)
- 应用Mapper.xml提供sql语句文件信息
- 提供SqlSession接口类实现select、insert、update、delete操作
框架端(JDBC封装)
读取配置文件
- 读取sqlMapperconfig.xml
- 读取Mapper.xml
解析配置文件
- 解析文件生成Configuration、MapperStatement对象
- 执行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 公布!