简易框架功能介绍
搭建这个简易的框架是为了加深对mybatis的理解,功能不是全部实现的(也没有能力),所以这个简易的框架的功能只支持表字段都为varchar,pojo为String类型的,而且本框架只支持JDBC事务管理器,只支持非池化,功能的话只实现了插入,查询(单个数据不支持多个)。
创建模块导入相关pom依赖
使用dom4j去进行解析xml文件
1. <?xml version="1.0" encoding="UTF-8"?> 2. <project xmlns="http://maven.apache.org/POM/4.0.0" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5. <modelVersion>4.0.0</modelVersion> 6. 7. <groupId>org.example</groupId> 8. <artifactId>mybatis-xml-dom4j</artifactId> 9. <version>1.0-SNAPSHOT</version> 10. <dependencies> 11. <!--dom4j依赖--> 12. <dependency> 13. <groupId>org.dom4j</groupId> 14. <artifactId>dom4j</artifactId> 15. <version>2.1.3</version> 16. </dependency> 17. <!--jaxen依赖--> 18. <dependency> 19. <groupId>jaxen</groupId> 20. <artifactId>jaxen</artifactId> 21. <version>1.2.0</version> 22. </dependency> 23. <!--junit依赖--> 24. <dependency> 25. <groupId>junit</groupId> 26. <artifactId>junit</artifactId> 27. <version>4.13.2</version> 28. <scope>test</scope> 29. </dependency> 30. </dependencies> 31. 32. <properties> 33. <maven.compiler.source>17</maven.compiler.source> 34. <maven.compiler.target>17</maven.compiler.target> 35. </properties> 36. 37. </project>
资源工具类
这个类用于读取指定配置文件的输入流,即读取resourse目录下的文件
1. /** 2. * @author 风轻云淡 3. */ 4. public class Resource { 5. /** 6. * 从类路径中获取配置文件输入输出流动 7. */ 8. public static InputStream getResourcesAsStream(String path){ 9. return Thread.currentThread().getContextClassLoader().getResourceAsStream(path); 10. } 11. }
sqlSessionFactoryBuilder工厂构造类
读取batis核心配置文件,工具SqlSessionFactory对象
build方法主要负责功能解析配置文件:
创建数据源对象
创建事物管理器对象
获取所有的SQL映射文件
1. /** 2. * @author 风轻云淡 3. */ 4. public class SqlSessionFactoryBuilder { 5. public SqlSessionFactoryBuilder() { 6. 7. } 8. 9. /** 10. * 获取SqlSessionFactory对象 11. * 读取batis核心配置文件,工具SqlSessionFactory对象 12. * @param inputStream 指向核心配置文件的输入流动 13. * @return 14. */ 15. public SqlSessionFactory build(InputStream inputStream){ 16. /** 17. * 主要负责功能解析配置文件 18. * 创建数据源对象 19. * 创建事物管理器对象 20. * 获取所有的SQL映射文件 21. * 封装到SqlSessionFactory对象中 22. * 23. */ 24. return null; 25. } 26. }
SqlSessionFactory设计和MappedStatement的编写
这个类应该包含:
一个属性为事务管理器,对应执行sql语句的MappedStatement对象
JDBCTransaction属性
Map<String, MappedStatement>属性
MappedStatement:
1. /** 2. * @author 风轻云淡 3. */ 4. public class MapperStatement { 5. private String sqlId; 6. private String resultType; 7. private String sql; 8. private String parameterType; 9. private String sqlType; 10. 11. public MapperStatement(String sqlId, String resultType, String sql, String parameterType, String sqlType) { 12. this.sqlId = sqlId; 13. this.resultType = resultType; 14. this.sql = sql; 15. this.parameterType = parameterType; 16. this.sqlType = sqlType; 17. } 18. 19. @Override 20. public String toString() { 21. return "MapperStatement{" + 22. "sqlId='" + sqlId + '\'' + 23. ", resultType='" + resultType + '\'' + 24. ", sql='" + sql + '\'' + 25. ", parameterType='" + parameterType + '\'' + 26. ", sqlType='" + sqlType + '\'' + 27. '}'; 28. } 29. 30. public String getSqlId() { 31. return sqlId; 32. } 33. 34. public void setSqlId(String sqlId) { 35. this.sqlId = sqlId; 36. } 37. 38. public String getResultType() { 39. return resultType; 40. } 41. 42. public void setResultType(String resultType) { 43. this.resultType = resultType; 44. } 45. 46. public String getSql() { 47. return sql; 48. } 49. 50. public void setSql(String sql) { 51. this.sql = sql; 52. } 53. 54. public String getParameterType() { 55. return parameterType; 56. } 57. 58. public void setParameterType(String parameterType) { 59. this.parameterType = parameterType; 60. } 61. 62. public String getSqlType() { 63. return sqlType; 64. } 65. 66. public void setSqlType(String sqlType) { 67. this.sqlType = sqlType; 68. } 69. 70. 71. }
JDBCTransaction设计
我们知道mybatis的事务管理器类型有只能填MANAGED或者JDBC,在本框架中我们只实现最简单的JDBC事务管理器
● transactionManager:配置事务管理器
○ type属性:指定事务管理器具体使用什么方式,可选值包括两个
■ JDBC:使用JDBC原生的事务管理机制。底层原理:事务开启conn.setAutoCommit(false); ...处理业务...事务提交conn.commit();
■ MANAGED:交给其它容器来管理事务,比如WebLogic、JBOSS等。如果没有管理事务的容器,则没有事务。没有事务的含义:只要执行一条DML语句,则提交一次。
事务管理器最好是定义一个接口,然后每一个具体的事务管理器都实现这个接口。
1. /** 2. * @author 风轻云淡 3. */ 4. public class JDBCTransaction implements TransactionManager{ 5. /** 6. * 数据库连接对象 7. */ 8. private Connection connection; 9. 10. /** 11. * 数据源对象 12. */ 13. private DataSource dataSource; 14. 15. /** 16. * 自动提交标记 17. * true:自动提交 18. * false:不自动提交 19. */ 20. private boolean autoCommit; 21. 22. /** 23. * 构造事务管理器对象 24. */ 25. public JDBCTransaction( DataSource dataSource,Connection connection) { 26. this.connection = connection; 27. this.dataSource = dataSource; 28. 29. } 30. 31. @Override 32. public void commit() { 33. try { 34. connection.commit(); 35. }catch (Exception e){ 36. e.printStackTrace(); 37. } 38. } 39. 40. @Override 41. public void rollback() { 42. try { 43. connection.rollback(); 44. } catch (SQLException throwables) { 45. throwables.printStackTrace(); 46. } 47. } 48. 49. @Override 50. public void close() { 51. try { 52. connection.close(); 53. } catch (SQLException throwables) { 54. throwables.printStackTrace(); 55. } 56. } 57. 58. @Override 59. public void openConnection() { 60. try { 61. Connection connection = dataSource.getConnection(); 62. this.connection.setAutoCommit(this.autoCommit); 63. } catch (SQLException throwables) { 64. throwables.printStackTrace(); 65. } 66. 67. } 68. 69. @Override 70. public Connection getConnection() { 71. return connection; 72. } 73. }
JDBC事务管理器实现类
1. /** 2. * @author 风轻云淡 3. */ 4. public class JDBCTransaction implements TransactionManager{ 5. @Override 6. public void commit() { 7. 8. } 9. 10. @Override 11. public void rollback() { 12. 13. } 14. 15. @Override 16. public void close() { 17. 18. } 19. 20. @Override 21. public void openConnection() { 22. 23. } 24. 25. @Override 26. public Connection getConnection() { 27. return null; 28. } 29. }
UNPOOLEDDataSource数据源类设计
unpool即在本框架中不使用数据库连接池技术实现
1. /** 2. * @author 风轻云淡 3. */ 4. public class UNPOOLEDDataSource implements javax.sql.DataSource{ 5. private String url; 6. private String username; 7. private String password; 8. 9. public UNPOOLEDDataSource(String driver,String url,String username,String password){ 10. try { 11. Class.forName(driver); 12. 13. }catch (Exception e){ 14. e.printStackTrace(); 15. } 16. this.url=url; 17. this.username=username; 18. this.password=password; 19. } 20. 21. 22. @Override 23. public Connection getConnection() throws SQLException { 24. return DriverManager.getConnection(url,username,password); 25. } 26. 27. @Override 28. public Connection getConnection(String username, String password) throws SQLException { 29. return null; 30. } 31. 32. @Override 33. public PrintWriter getLogWriter() throws SQLException { 34. return null; 35. } 36. 37. @Override 38. public void setLogWriter(PrintWriter out) throws SQLException { 39. 40. } 41. 42. @Override 43. public void setLoginTimeout(int seconds) throws SQLException { 44. 45. } 46. 47. @Override 48. public int getLoginTimeout() throws SQLException { 49. return 0; 50. } 51. 52. @Override 53. public Logger getParentLogger() throws SQLFeatureNotSupportedException { 54. return null; 55. } 56. 57. @Override 58. public <T> T unwrap(Class<T> iface) throws SQLException { 59. return null; 60. } 61. 62. @Override 63. public boolean isWrapperFor(Class<?> iface) throws SQLException { 64. return false; 65. } 66. }
SqlSessionFactory类完善
1. /** 2. * @author 风轻云淡 3. */ 4. public class SqlSessionFactory { 5. private TransactionManager transactionManager; 6. private Map<String,MapperStatement> mapperStatements; 7. 8. public SqlSessionFactory(TransactionManager transactionManager, Map<String, MapperStatement> mapperStatements) { 9. this.transactionManager = transactionManager; 10. this.mapperStatements = mapperStatements; 11. } 12. 13. public TransactionManager getTransactionManager() { 14. return transactionManager; 15. } 16. 17. public void setTransactionManager(TransactionManager transactionManager) { 18. this.transactionManager = transactionManager; 19. } 20. 21. public Map<String, MapperStatement> getMapperStatements() { 22. return mapperStatements; 23. } 24. 25. public void setMapperStatements(Map<String, MapperStatement> mapperStatements) { 26. this.mapperStatements = mapperStatements; 27. } 28. }
SqlSessionFactoryBuilder中的build方法编写
1. /** 2. * @author 风轻云淡 3. */ 4. public class SqlSessionFactoryBuilder { 5. public SqlSessionFactoryBuilder() { 6. 7. } 8. 9. /** 10. * 获取SqlSessionFactory对象 11. * 读取batis核心配置文件,工具SqlSessionFactory对象 12. * @param inputStream 指向核心配置文件的输入流动 13. * @return 14. */ 15. public SqlSessionFactory build(InputStream inputStream) throws DocumentException { 16. /** 17. * 主要负责功能解析配置文件 18. * 创建数据源对象 19. * 创建事物管理器对象 20. * 获取所有的SQL映射文件 21. * 封装到SqlSessionFactory对象中 22. * 23. */ 24. Document document = new SAXReader().read(inputStream); 25. Element environmentsElt = (Element) document.selectSingleNode("/configuration/environments"); 26. String defaultEnv = environmentsElt.attributeValue("default"); 27. //解析文件得出数据源对象 28. Element dataSourceElt = environmentsElt.element("dataSource"); 29. DataSource dataSource= getDataSource(dataSourceElt); 30. //解析文件得出事务管理器对象 31. Element transactionManagerElt = environmentsElt.element("transactionManager"); 32. TransactionManager transactionManager =gettransactionManager(transactionManagerElt,dataSource); 33. //解析文件得出sql映射对象 34. Element mapperElt=environmentsElt.element("mappers"); 35. Map<String,MapperStatement> mapperStatementMap =getMapperStatements(mapperElt); 36. SqlSessionFactory sqlSessionFactory = new SqlSessionFactory(transactionManager, mapperStatementMap); 37. return sqlSessionFactory; 38. } 39. 40. private Map<String, MapperStatement> getMapperStatements(Element mapperElt) { 41. Map<String,MapperStatement> mapperStatements=new HashMap<>(); 42. try { 43. String resource = mapperElt.attributeValue("resource"); 44. SAXReader saxReader = new SAXReader(); 45. Document document = saxReader.read(Resource.getResourcesAsStream(resource)); 46. Element mapper = (Element) document.selectSingleNode("/mapper"); 47. String namespace = mapper.attributeValue("namespace"); 48. mapper.elements().forEach(item->{ 49. String sqlId = item.attributeValue("id"); 50. String sql = item.getTextTrim(); 51. String parameterType = item.attributeValue("parameterType"); 52. String resultType = item.attributeValue("resultType"); 53. String sqlType = item.getName().toLowerCase(); 54. //封装对象 55. MapperStatement mapperStatement = new MapperStatement(sqlId, resultType, sql, parameterType, sqlType); 56. mapperStatements.put(namespace+"."+sqlId,mapperStatement); 57. 58. }); 59. 60. }catch (Exception e){ 61. e.printStackTrace(); 62. } 63. return mapperStatements; 64. } 65. 66. private TransactionManager gettransactionManager(Element transactionManagerElt, DataSource dataSource) { 67. String type = transactionManagerElt.attributeValue("type").toUpperCase(); 68. TransactionManager transactionManager=null; 69. if("JDBC".equals(type)){ 70. transactionManager=new JDBCTransaction(dataSource,false); 71. }else{ 72. try { 73. throw new Exception("本框架只支持JDBC事务管理"); 74. } catch (Exception e) { 75. e.printStackTrace(); 76. } 77. }; 78. return transactionManager; 79. } 80. 81. private DataSource getDataSource(Element dataSourceElt) { 82. //获取所有数据源配置 83. Map<String ,String> dataSourceMap=new HashMap<>(); 84. dataSourceElt.elements().forEach(item->{ 85. dataSourceMap.put(item.attributeValue("name"),item.attributeValue("value")); 86. }); 87. String dataSourceType = dataSourceElt.attributeValue("type").toUpperCase(); 88. DataSource dataSource=null; 89. if("UNPOOLED".equals(dataSourceType)){ 90. dataSource=new UNPOOLEDDataSource(dataSourceMap.get("driver"), 91. dataSourceMap.get("url"), 92. dataSourceMap.get("username"), 93. dataSourceMap.get("password")); 94. }else{ 95. try { 96. throw new Exception("本框架只实现了UNPOOLED"); 97. } catch (Exception e) { 98. e.printStackTrace(); 99. } 100. } 101. return dataSource; 102. } 103. }
SqlSession编写
1. public class SqlSession { 2. TransactionManager transactionManager; 3. Map<String, MapperStatement> mapperStatements; 4. 5. public SqlSession(TransactionManager transactionManager, Map<String, MapperStatement> mapperStatements) { 6. this.transactionManager = transactionManager; 7. this.mapperStatements = mapperStatements; 8. } 9. public void commit(){ 10. try { 11. transactionManager.getConnection().commit(); 12. } catch (SQLException e) { 13. throw new RuntimeException(e); 14. } 15. } 16. 17. public void rollback(){ 18. try { 19. transactionManager.getConnection().rollback(); 20. } catch (SQLException e) { 21. throw new RuntimeException(e); 22. } 23. } 24. 25. public void close(){ 26. try { 27. transactionManager.getConnection().close(); 28. } catch (SQLException e) { 29. throw new RuntimeException(e); 30. } 31. } 32. }
在SqlSessionFactory中添加openSession方法
1. public SqlSession openSession(){ 2. transactionManager.openConnection(); 3. SqlSession sqlSession = new SqlSession(transactionManager, mappedStatements); 4. return sqlSession; 5. }
编写SqlSession类中的insert方法
1. /** 2. * 插入数据 3. * 4. * @param sqlId 要执行的sqlId 5. * @param obj 插入的数据 6. * @return 7. */ 8. public int insert(String sqlId, Object obj) { 9. MapperStatement godMappedStatement = mapperStatements.get(sqlId); 10. Connection connection = transactionManager.getConnection(); 11. // 获取sql语句 12. // insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType}) 13. String godbatisSql = godMappedStatement.getSql(); 14. // insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?) 15. String sql = godbatisSql.replaceAll("#\\{[a-zA-Z0-9_\\$]*}", "?"); 16. 17. // 重点一步 18. Map<Integer, String> map = new HashMap<>(); 19. int index = 1; 20. while (godbatisSql.indexOf("#") >= 0) { 21. int beginIndex = godbatisSql.indexOf("#") + 2; 22. int endIndex = godbatisSql.indexOf("}"); 23. map.put(index++, godbatisSql.substring(beginIndex, endIndex).trim()); 24. godbatisSql = godbatisSql.substring(endIndex + 1); 25. } 26. 27. final PreparedStatement ps; 28. try { 29. ps = connection.prepareStatement(sql); 30. 31. // 给?赋值 32. map.forEach((k, v) -> { 33. try { 34. // 获取java实体类的get方法名 35. String getMethodName = "get" + v.toUpperCase().charAt(0) + v.substring(1); 36. Method getMethod = obj.getClass().getDeclaredMethod(getMethodName); 37. ps.setString(k, getMethod.invoke(obj).toString()); 38. } catch (Exception e) { 39. throw new RuntimeException(e); 40. } 41. }); 42. int count = ps.executeUpdate(); 43. ps.close(); 44. return count; 45. } catch (Exception e) { 46. throw new RuntimeException(e); 47. } 48. }
编写SqlSession类中的selectOne方法
1. /** 2. * 查询一个对象 3. * @param sqlId 4. * @param parameterObj 5. * @return 6. */ 7. public Object selectOne(String sqlId, Object parameterObj){ 8. MapperStatement godMappedStatement = mapperStatements.get(sqlId); 9. Connection connection = transactionManager.getConnection(); 10. // 获取sql语句 11. String godbatisSql = godMappedStatement.getSql(); 12. String sql = godbatisSql.replaceAll("#\\{[a-zA-Z0-9_\\$]*}", "?"); 13. // 执行sql 14. PreparedStatement ps = null; 15. ResultSet rs = null; 16. Object obj = null; 17. try { 18. ps = connection.prepareStatement(sql); 19. ps.setString(1, parameterObj.toString()); 20. rs = ps.executeQuery(); 21. if (rs.next()) { 22. // 将结果集封装对象,通过反射 23. String resultType = godMappedStatement.getResultType(); 24. Class<?> aClass = Class.forName(resultType); 25. Constructor<?> con = aClass.getDeclaredConstructor(); 26. obj = con.newInstance(); 27. // 给对象obj属性赋值 28. ResultSetMetaData rsmd = rs.getMetaData(); 29. int columnCount = rsmd.getColumnCount(); 30. for (int i = 1; i <= columnCount; i++) { 31. String columnName = rsmd.getColumnName(i); 32. String setMethodName = "set" + columnName.toUpperCase().charAt(0) + columnName.substring(1); 33. Method setMethod = aClass.getDeclaredMethod(setMethodName, aClass.getDeclaredField(columnName).getType()); 34. setMethod.invoke(obj, rs.getString(columnName)); 35. } 36. } 37. } catch (Exception e) { 38. throw new RuntimeException(e); 39. } finally { 40. if (rs != null) { 41. try { 42. rs.close(); 43. } catch (SQLException e) { 44. throw new RuntimeException(e); 45. } 46. } 47. try { 48. ps.close(); 49. } catch (SQLException e) { 50. throw new RuntimeException(e); 51. } 52. } 53. return obj; 54. }