引言 在上一章中,我们实现了读取mapper配置并构造相关的mapper代理对象,读取mapper.xml文件中的sql信息等操作,现在,在上一章的基础上,我们接着开始链接数据库,通过封装JDBC,来实现我们数据库操作。
数据库准备 我们创建一个user表,用于后续进行测试,user表的结构如下图所示:
user表的内容如下:
添加User类 我们根据表结构,创建对应的user类,user类的结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 package com.yang.mybatis.test; import java.io.Serializable; import java.util.Date; public class User implements Serializable { private Integer id; private String userName; private String password; private Integer age; private Date createTime; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } }
JDBC基础操作 在使用jdbc之前,我们先引入mysql的依赖
1 2 3 4 5 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0 .27 </version> </dependency>
jdbc的操作,一般分为下面几个步骤: 1)加载JDBC驱动程序 2)创建数据库链接 3)创建一个preparedStatement 4)执行SQL语句 5)遍历数据集 6)处理异常,关闭JDBC对象资源 示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public static void main(String[ ] args) throws SQLException { String url = "jdbc:mysql://localhost:3306/test?useSSL=false" ; String username = "root" ; String password = "3fa4d180" ; Connection conn = null ; try { Class.forName("com.mysql.cj.jdbc.Driver" ); conn = DriverManager.getConnection(url, username, password); conn.setAutoCommit(false ); String sql = "select user_name from user where id = ?" ; PreparedStatement preparedStatement = conn.prepareStatement(sql); preparedStatement.setInt(1 , 1 ); ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { System.out.println(resultSet.getString(1 )); } conn.commit(); } catch (SQLException | ClassNotFoundException e) { conn.rollback(); e.printStackTrace(); } finally { conn.close(); } }
执行上述代码,结果如下:
将sql操作,收敛到SqlSession 在上一章,当我们调用mapper的方法时,最终是通过在MapperProxy中获取对应的MybatisStatement,然后打印出sql信息的,但是如果后续操作数据库是,也在MapperProxy中执行sql的话,不太方便管理。因此,我们添加一个IMybatisSqlSession类,后续对于数据库的操作,收敛到此类进行。 首先,我们添加IMybatisSqlSession:
1 2 3 4 5 6 7 8 9 package com.yang.mybatis.session; public interface IMybatisSqlSession { <T> T execute(String method, Object parameter); <T> T getMapper(Class<T> type);}
然后添加其默认实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.yang.mybatis.session; import com.yang.mybatis.proxy.MapperProxyFactory; public class DefaultMybatisSqlSession implements IMybatisSqlSession { private MapperProxyFactory mapperProxyFactory; public DefaultMybatisSqlSession(MapperProxyFactory mapperProxyFactory) { this.mapperProxyFactory = mapperProxyFactory; } @Override public <T> T execute(String method, Object parameter) { return (T)("你被代理了!" + method + ",入参:" + parameter); } @Override public <T> T getMapper(Class<T> type) { return (T) mapperProxyFactory.newInstance(type, this); } }
添加IMybatisSqlSession的工厂接口
1 2 3 4 5 6 package com.yang.mybatis.session; public interface MybatisSqlSessionFactory { IMybatisSqlSession openSession();}
添加工厂的默认实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.yang.mybatis.session; import com.yang.mybatis.proxy.MapperProxyFactory; public class DefaultMybatisSqlSessionFactory implements IMybatisSqlSessionFactory { private MapperProxyFactory mapperProxyFactory; public DefaultMybatisSqlSessionFactory(MapperProxyFactory mapperProxyFactory) { this.mapperProxyFactory = mapperProxyFactory; } @Override public IMybatisSqlSession openSession() { return new DefaultMybatisSqlSession(mapperProxyFactory); } }
修改MapperProxyFactory,在新建MapperProxy的时候,将imybatisSqlSession传递给MapperProxy。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package com.yang.mybatis.proxy; import com.yang.mybatis.config.MybatisConfiguration; import com.yang.mybatis.session.IMybatisSqlSession; import java.lang.reflect.Proxy; public class MapperProxyFactory { private MybatisConfiguration mybatisConfiguration; public MapperProxyFactory(MybatisConfiguration mybatisConfiguration) { this.mybatisConfiguration = mybatisConfiguration; } public Object newInstance(Class mapperType, IMybatisSqlSession mybatisSqlSession) { MapperProxy mapperProxy = new MapperProxy(mapperType, mybatisSqlSession); return Proxy.newProxyInstance(mapperType.getClassLoader(), new Class[ ] { mapperType} , mapperProxy); } public MybatisConfiguration getMybatisConfiguration() { return mybatisConfiguration; } public void setMybatisConfiguration(MybatisConfiguration mybatisConfiguration) { this.mybatisConfiguration = mybatisConfiguration; } }
然后修改MapperProxy,在真正执行的时候,通过iMybatisSqlSession的execute,来执行sql操作,以此实现sql操作由iMybatisSqlSession来统一管理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package com.yang.mybatis.proxy; import com.yang.mybatis.session.IMybatisSqlSession; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MapperProxy<T> implements InvocationHandler { private Class<T> mapperInterface; private IMybatisSqlSession sqlSession; public MapperProxy(Class<T> mapperInterface, IMybatisSqlSession mybatisSqlSession) { this.mapperInterface = mapperInterface; this.sqlSession = mybatisSqlSession; } @Override public Object invoke(Object proxy, Method method, Object[ ] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } String methodName = this.mapperInterface.getName() + "." + method.getName(); return sqlSession.execute(methodName, args); } }
最后,我们添加sqlSession工厂类的创建者,通过创建者模式,来创建SqlSession工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package com.yang.mybatis.session; import com.yang.mybatis.config.MybatisConfiguration; import com.yang.mybatis.config.MybatisSqlStatement; import com.yang.mybatis.config.parser.IMybatisConfigurationParser; import com.yang.mybatis.config.parser.IMybatisMapperParser; import com.yang.mybatis.proxy.MapperProxyFactory; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class MybatisSqlSessionFactoryBuilder { private IMybatisConfigurationParser mybatisConfigurationParser; private IMybatisMapperParser mybatisMapperParser; private String configPath; public IMybatisSqlSessionFactory buildSqlSessionFactory() { if (configPath == null || configPath.isEmpty()) { throw new RuntimeException("配置文件路径不合法==========" ); } if (this.mybatisMapperParser == null || this.mybatisConfigurationParser == null ) { throw new RuntimeException("缺少解析器=======" ); } MybatisConfiguration mybatisConfiguration = mybatisConfigurationParser.parser(configPath); List<String> mapperPaths = mybatisConfiguration.getMapperPaths(); for (String mapperPath : mapperPaths) { List<MybatisSqlStatement> mybatisSqlStatements = this.mybatisMapperParser.parseMapper(mapperPath); Map<String, List<MybatisSqlStatement>> mapperNameGroupMap = mybatisSqlStatements.stream() .collect(Collectors.groupingBy(MybatisSqlStatement: : getNamespace)); for (Map.Entry<String, List<MybatisSqlStatement>> entry : mapperNameGroupMap.entrySet()) { String mapperName = entry.getKey(); List<MybatisSqlStatement> sqlSessionList = entry.getValue(); mybatisConfiguration.putMybatisSqlStatementList(mapperName, sqlSessionList); } } MapperProxyFactory mapperProxyFactory = new MapperProxyFactory(mybatisConfiguration); return new DefaultMybatisSqlSessionFactory(mapperProxyFactory); } public MybatisSqlSessionFactoryBuilder setConfigPath(String configPath) { this.configPath = configPath; return this; } public MybatisSqlSessionFactoryBuilder setMybatisConfigurationParser(IMybatisConfigurationParser iMybatisConfigurationParser) { this.mybatisConfigurationParser = iMybatisConfigurationParser; return this; } public MybatisSqlSessionFactoryBuilder setMybatisMapperParser(IMybatisMapperParser iMybatisMapperParser) { this.mybatisMapperParser = iMybatisMapperParser; return this; } }
添加测试代码,进行测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package com.yang.mybatis.test; import com.yang.mybatis.config.parser.XmlMybatisConfigurationParser; import com.yang.mybatis.config.parser.XmlMybatisMapperParser; import com.yang.mybatis.session.IMybatisSqlSession; import com.yang.mybatis.session.IMybatisSqlSessionFactory; import com.yang.mybatis.session.MybatisSqlSessionFactoryBuilder; public class Main { public static void main(String[ ] args) { String configPath = "mybatis-config.xml" ; IMybatisSqlSessionFactory mybatisSqlSessionFactory = new MybatisSqlSessionFactoryBuilder() .setMybatisMapperParser(new XmlMybatisMapperParser()) .setMybatisConfigurationParser(new XmlMybatisConfigurationParser()) .setConfigPath(configPath) .buildSqlSessionFactory(); IMybatisSqlSession mybatisSqlSession = mybatisSqlSessionFactory.openSession(); IUserMapper userMapper = mybatisSqlSession.getMapper(IUserMapper.class); System.out.println(userMapper.queryUserName(1 )); } }
SqlSession获取执行方法对应的sql语句 首先,修改MybatisConfiguration,之前是将每一个mapper和他所拥有的MybatisSqlStatement列表关联起来,现在感觉粒度太大,因此,该为每一个mapper的方法和对应的MybatisSqlStatement关联。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package com.yang.mybatis.config; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MybatisConfiguration implements Serializable { private Map<String, MybatisEnvironment> id2EnvironmentMap = new HashMap<>(); private MybatisEnvironment defaultMybatisEnvironment; private List<String> mapperPaths = new ArrayList<>(); private Map<String, MybatisSqlStatement> mapperMethod2SqlStatementsMap = new HashMap<>(); public void putMapperMethod2MybatisSqlStatement(String mapperMethod, MybatisSqlStatement mybatisSqlStatement) { this.mapperMethod2SqlStatementsMap.put(mapperMethod, mybatisSqlStatement); } public MybatisSqlStatement getMybatisSqlStatement(String mapperMethod) { return this.mapperMethod2SqlStatementsMap.get(mapperMethod); } public Map<String, MybatisSqlStatement> getMapperMethod2SqlStatementsMap() { return this.mapperMethod2SqlStatementsMap; } public void addEnvironment(String id, MybatisEnvironment mybatisEnvironment) { this.id2EnvironmentMap.put(id, mybatisEnvironment); } public MybatisEnvironment getEnvironment(String id) { return id2EnvironmentMap.get(id); } public MybatisEnvironment getDefaultMybatisEnvironment() { return defaultMybatisEnvironment; } public void setDefaultMybatisEnvironment(MybatisEnvironment defaultMybatisEnvironment) { this.defaultMybatisEnvironment = defaultMybatisEnvironment; } public void addMapperPath(String mapperPath) { this.mapperPaths.add(mapperPath); } public List<String> getMapperPaths() { return this.mapperPaths; } public List<MybatisEnvironment> getEnvironments() { return new ArrayList<>(id2EnvironmentMap.values()); } }
然后修改MybatisSqlSessionFactoryBuilder:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package com.yang.mybatis.session; import com.yang.mybatis.config.MybatisConfiguration; import com.yang.mybatis.config.MybatisSqlStatement; import com.yang.mybatis.config.parser.IMybatisConfigurationParser; import com.yang.mybatis.config.parser.IMybatisMapperParser; import com.yang.mybatis.proxy.MapperProxyFactory; import java.util.List; public class MybatisSqlSessionFactoryBuilder { private IMybatisConfigurationParser mybatisConfigurationParser; private IMybatisMapperParser mybatisMapperParser; private String configPath; public IMybatisSqlSessionFactory buildSqlSessionFactory() { if (configPath == null || configPath.isEmpty()) { throw new RuntimeException("配置文件路径不合法==========" ); } if (this.mybatisMapperParser == null || this.mybatisConfigurationParser == null ) { throw new RuntimeException("缺少解析器=======" ); } MybatisConfiguration mybatisConfiguration = mybatisConfigurationParser.parser(configPath); List<String> mapperPaths = mybatisConfiguration.getMapperPaths(); for (String mapperPath : mapperPaths) { List<MybatisSqlStatement> mybatisSqlStatements = this.mybatisMapperParser.parseMapper(mapperPath); for (MybatisSqlStatement mybatisSqlStatement : mybatisSqlStatements) { String methodName = mybatisSqlStatement.getNamespace() + "." + mybatisSqlStatement.getId(); mybatisConfiguration.putMapperMethod2MybatisSqlStatement(methodName, mybatisSqlStatement); } } MapperProxyFactory mapperProxyFactory = new MapperProxyFactory(mybatisConfiguration); return new DefaultMybatisSqlSessionFactory(mapperProxyFactory); } public MybatisSqlSessionFactoryBuilder setConfigPath(String configPath) { this.configPath = configPath; return this; } public MybatisSqlSessionFactoryBuilder setMybatisConfigurationParser(IMybatisConfigurationParser iMybatisConfigurationParser) { this.mybatisConfigurationParser = iMybatisConfigurationParser; return this; } public MybatisSqlSessionFactoryBuilder setMybatisMapperParser(IMybatisMapperParser iMybatisMapperParser) { this.mybatisMapperParser = iMybatisMapperParser; return this; } }
修改DefaultMybatisSqlSession类,获取方法对应的MybatisStatement
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package com.yang.mybatis.session; import com.yang.mybatis.config.MybatisSqlStatement; import com.yang.mybatis.proxy.MapperProxyFactory; public class DefaultMybatisSqlSession implements IMybatisSqlSession { private MapperProxyFactory mapperProxyFactory; public DefaultMybatisSqlSession(MapperProxyFactory mapperProxyFactory) { this.mapperProxyFactory = mapperProxyFactory; } @Override public <T> T execute(String method, Object parameter) { MybatisSqlStatement mybatisSqlStatement = this.mapperProxyFactory.getMybatisConfiguration().getMybatisSqlStatement(method); return (T)("method:" + method + "sql:" + mybatisSqlStatement.getSql() + ",入参:" + parameter); } @Override public <T> T getMapper(Class<T> type) { return (T) mapperProxyFactory.newInstance(type, this); } }
添加测试方法进行测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 public static void main(String[ ] args) { String configPath = "mybatis-config.xml" ; MybatisSqlSessionFactory mybatisSqlSessionFactory = new MybatisSqlSessionFactoryBuilder() .setMybatisMapperParser(new XmlMybatisMapperParser()) .setMybatisConfigurationParser(new XmlMybatisConfigurationParser()) .setConfigPath(configPath) .buildSqlSessionFactory(); IMybatisSqlSession mybatisSqlSession = mybatisSqlSessionFactory.openSession(); IUserMapper userMapper = mybatisSqlSession.getMapper(IUserMapper.class); System.out.println(userMapper.queryUserAge(1 )); }
测试结果如下:
参考文章 https://blog.csdn.net/weixin_43520450/article/details/107230205