----简单自定义mybatis流程----
一.首先封装daoMapperxml文件和sqlMapconfig配置文件,如何封装:(1).封装我们的Mapper.xml文件,提取名称空间namespace,提取方法名id,提取我们的结果类型resultType,再提取我们的sql语句sqlStatement创建实例对象封装.(2).封装我们的sqlMapconfig.xml操作数据库的配置文件,提取数据源datasource(c3p0,德鲁伊...),再提取连接数据库四个步骤:driver驱动,地址URL,用户名username和密码password,还有最后一个接口映射文件信息,由于实际开发中会有多个,所以可以使用一个Map集合来定义Map<String,Mapper>datasource,接着创建实例封装.二.解析xml文件,这里使用dom4j解析,然后创建我们的数据源对象:(1).解析sqlMapconfig.xml文件//这边使用无参构造方法来解析xml文件和加载数据源datasource! public Configuration(){ loadXpathSqlMapConfig(); creatDatasource(); }/**
* 解析数据库配置文件 */ public void loadXpathSqlMapConfig(){ try { //通过类加载器加载配置文件 InputStream resource = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml"); //采用dom4j解析xml配置文件 SAXReader saxReader = new SAXReader(); Document read = saxReader.read(resource); Element rootElement = read.getRootElement(); //System.out.println(rootElement); List<Element> nodesList = rootElement.selectNodes("//property");//语法要求要加"//" for (Element element : nodesList) { String name = element.attributeValue("name"); String value = element.attributeValue("value"); if ("driver".equals(name)){ driver=value; } if ("url".equals(name)){ url=value; } if ("username".equals(name)){ username=value; } if ("password".equals(name)){ password=value; } } List<Element> list = rootElement.selectNodes("//mapper"); for (Element element : list) { String xpath = element.attributeValue("resource"); loadMapperXml(xpath);} catch (Exception e) {
e.printStackTrace(); } }/**
* 创建数据源对象设置连接数据库参数 * */ public void creatDatasource(){try {
//创建数据源对象 dataSource = new ComboPooledDataSource(); dataSource.setDriverClass(driver); dataSource.setJdbcUrl(url); dataSource.setUser(username); dataSource.setPassword(password);} catch (Exception e) {
e.printStackTrace(); }}
(2).解析interfaceMapperXml文件.封装到我们的Mapper中!/** * 解析interfaceMapperXml文件 * @param xpath */ public void loadMapperXml(String xpath) { mappers = new HashMap<>(); try { InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(xpath); SAXReader saxReader = new SAXReader(); Document document = saxReader.read(inputStream); Element rootElement = document.getRootElement(); String namespace = rootElement.attributeValue("namespace"); List<Element> elements = rootElement.elements(); Mapper mapper = new Mapper(); for (Element element : elements) { String id = element.attributeValue("id"); String resultType = element.attributeValue("resultType"); String sqlStatement = element.getText(); mapper.setId(id); mapper.setNamespace(namespace); mapper.setResultType(resultType); mapper.setSqlStatement(sqlStatement); String key=namespace+"."+id; mappers.put(key,mapper); } } catch (Exception e) { e.printStackTrace(); } }三.创建核心对象SqlSession对象,旧版Mybatis前常用SqlSession对象中的增删查改方法,现在新版Myatis常用getMapper方法,面向接口的编程方式,需要接口名与mapper的命名空间属性值保持一致,从而将接口与mapper文件对应起来。当namespace绑定某一接口之后,可以不用写该接口的实现类,MyBatis会通过接口的完整限定名查找到对应的mapper配置来执行SQL语句.里边使用了动态代理技术.public class SqlSession { public <T> T getMapper(Class<T> type){ T proxy= (T) Proxy.newProxyInstance( this.getClass().getClassLoader(), new Class[]{type}, new MapperProxy());
return proxy;
}}public class MapperProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //加载映射文件和配置文件 Configuration configuration = new Configuration(); //数据源 ComboPooledDataSource dataSource = configuration.getDataSource(); //执行的sql语句 Map<String, Mapper> mappers = configuration.getMappers(); String methodName = method.getName(); String className = method.getDeclaringClass().getName();String key=className+"."+methodName;
System.out.println(key); Mapper mapper = mappers.get(key);return Executor.findAll(mapper,dataSource.getConnection());
}}四.创建我们的SqlSessionFactory会话工厂对象,通过里面的openSession()方法打开(得到)我们的核心Sqlsession会话对象; * @Description: 会话工厂对象对象,此对象提供一个openSession()方法 */public class SqlSessionFactory { public static SqlSession openSession(){ return new SqlSession(); }}五.创建Executor工具类 执行数据库操作并且封装结果集返回:public class Executor { public static <T> List<T> findAll(Mapper mapper, Connection connection){List<T> resultList =new ArrayList<T>();
PreparedStatement preparedStatement=null; ResultSet resultSet=null; try { //获取到sql语句 String sqlStatement = mapper.getSqlStatement(); //获取返回值类型 String resultType = mapper.getResultType(); //转成字节码对象 Class<?> aClass = Class.forName(resultType); preparedStatement = connection.prepareStatement(sqlStatement); //执行完返回resultSet 封装结果集 resultSet = preparedStatement.executeQuery(); handleResult(resultList,aClass,resultSet); } catch (Exception e) { e.printStackTrace(); }finally { close(connection,preparedStatement,resultSet); } return resultList;}
/**
* 处理结果集方法 * @param resultList * @param aClass * @param resultSet */ private static void handleResult(List resultList, Class<?> aClass, ResultSet resultSet) { try { //首先获取到元数据 ResultSetMetaData metaData = resultSet.getMetaData(); //获取元数据字段数量 int columnCount = metaData.getColumnCount();//获取字段名称,因为多个,所以使用数组保存
String[] columnNames= new String[columnCount]; for (int i = 1; i <= columnNames.length; i++) { columnNames[i-1]= metaData.getColumnName(i); } //循环取数据 while (resultSet.next()){ //通过反射技术给成员变量赋值 Object o = aClass.newInstance();//这个对象表示是User对象 //便利字段名称数组 for (int i = 0; i < columnNames.length; i++) { //resultSet.getObject():获取此的当前行中指定列的值 Object object = resultSet.getObject(columnNames[i]);Field field = aClass.getDeclaredField(columnNames[i]);
field.setAccessible(true); field.set(o,object); } resultList.add(o) ; }} catch (Exception e) {
e.printStackTrace(); }}
/**
* 释放资源 * @param connection * @param preparedStatement * @param resultSet */ private static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) { try { if (connection!=null) connection.close(); if (preparedStatement!=null) preparedStatement.close(); if (resultSet!=null) resultSet.close(); } catch (Exception e) { e.printStackTrace(); } }
}
六.测试:
public class MybatisTest {public static void main(String[] args) {
//测试
SqlSession sqlSession = SqlSessionFactory.openSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userList = mapper.findAll(); for (User user : userList) { System.out.println(user); } }}输出测试数据如下: