mybatis3使用@Select等注解實(shí)現(xiàn)增刪改查操作
1.需要的jar包
2.目錄樹(shù)
3.具體代碼
一.需要的jar包
第一個(gè):mybatis的jar包
第二個(gè):mysql數(shù)據(jù)的驅(qū)動(dòng)
二.目錄樹(shù)
三.具體代碼
使用框架,配置文件先行!
conf.xml:(配置 登錄數(shù)據(jù)庫(kù),映射文件)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/> <property name="username" value="root"/> <property name="password" value="zhujunwen"/> </dataSource> </environment> </environments> <!-- 配置映射--> <mappers> <!-- 若映射文件mapper 是xml,則<mapper recourse...>,若映射文件為java文件,則<mapper class.....> --> <mapper class="com.UserMapper"/> </mappers> </configuration>
映射文件:
UserMapper.java:(用于映射SQL語(yǔ)句)
package com; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; public interface UserMapper { /* 這個(gè)一個(gè)接口,但不需要實(shí)現(xiàn)它,用于 函數(shù)與SQL語(yǔ)句 的映射 * */ @Insert("insert into tb_user(name,sex) values(#{name},#{sex})") public void insertT(User user); @Delete("delete from tb_user where id=#{id}") public void deleteById(int id); @Update("update tb_user set name=#{name},sex=#{sex} where id=#{id}") public void updateT(User user); @Select("select * from tb_user where id=#{id}") public User getUser(int id); @Select("select * from tb_user") public List<User> getAllUsers(); }
持久類:
User.java:(持久類中的成員變量要與數(shù)據(jù)表中的字段名字一致)
package com; public class User { private Integer id; private String name; private String sex; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String toString() { return "User [id=" + id + ", name=" + name + ", sex=" + sex + "]"; } }
必要變量的快速獲?。海ǐ@取Session)
FKSqlSessionFactory.java:
package com; import java.io.IOException; import java.io.InputStream; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class FKSqlSessionFactory { private static SqlSessionFactory sqlSessionFactory = null; static{ InputStream input; try { input = Resources.getResourceAsStream("conf.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(input); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } public static SqlSessionFactory getSqlSessionFactory(){ return sqlSessionFactory; } }
測(cè)試文件(只是演示對(duì)數(shù)據(jù)庫(kù)的插入)
package com; import java.util.ArrayList; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; public class Test1 { public static void main(String[] args) { SqlSessionFactory factory= FKSqlSessionFactory.getSqlSessionFactory(); SqlSession session = factory.openSession(); UserMapper mapper = session.getMapper(UserMapper.class);//獲取映射器實(shí)例 User user = new User(); user.setName("zhujunwen"); user.setSex("m"); mapper.insertT(user); //調(diào)用映射器中的insertT()方法進(jìn)行數(shù)據(jù)庫(kù)插入 session.commit(); session.close(); } }
效果:
已有數(shù)據(jù)插入到數(shù)據(jù)表
數(shù)據(jù)表的樣式:
補(bǔ)充知識(shí):mybatis 一次select操作執(zhí)行流程分析
1.測(cè)試代碼
package com.testmybatis; import java.io.IOException; import java.io.InputStream; import java.util.List; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.log4j.Logger; import com.alibaba.fastjson.JSON; import com.testmybatis.dao.TestMapper; import com.testmybatis.model.Test; public class testlanjie { private static Logger log=Logger.getLogger(testlanjie.class); public static void main(String args[]){ List<Test> tests=null; try { String resource = "com/testmybatis/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); try { TestMapper mapper=session.getMapper(TestMapper.class); tests=mapper.test(); session.commit(); } finally { session.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(tests!=null) log.info(JSON.toJSONString(tests)); } }
2.流程分析
第一步構(gòu)造SqlSessionFactory
String resource = "com/testmybatis/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactoryBuilder下的build函數(shù)
public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null); } public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
先用配置文件的文件流對(duì)象構(gòu)造一個(gè)XMLConfigBuilder對(duì)象,在調(diào)用parse函數(shù)得到Configuration對(duì)象
public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; parseConfiguration(parser.evalNode("/configuration")); return configuration; } private void parseConfiguration(XNode root) { try { Properties settings = settingsAsPropertiess(root.evalNode("settings")); //issue #117 read properties first propertiesElement(root.evalNode("properties")); loadCustomVfs(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); }
其中mybatis主要的配置都在這里完成,存放在configuration中,本次分析會(huì)用到的兩個(gè)函數(shù)是environmentsElement和mapperElement,一個(gè)是構(gòu)造datasource,一個(gè)是構(gòu)造存放所有MapperProxyFactory的MapperRegistry,相應(yīng)的源代碼如下
private void environmentsElement(XNode context) throws Exception { if (context != null) { if (environment == null) { environment = context.getStringAttribute("default"); } for (XNode child : context.getChildren()) { String id = child.getStringAttribute("id"); if (isSpecifiedEnvironment(id)) { TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); DataSource dataSource = dsFactory.getDataSource(); Environment.Builder environmentBuilder = new Environment.Builder(id) .transactionFactory(txFactory) .dataSource(dataSource); configuration.setEnvironment(environmentBuilder.build()); } } } } private void mapperElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { if ("package".equals(child.getName())) { String mapperPackage = child.getStringAttribute("name"); configuration.addMappers(mapperPackage); } else { String resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); String mapperClass = child.getStringAttribute("class"); if (resource != null && url == null && mapperClass == null) { ErrorContext.instance().resource(resource); InputStream inputStream = Resources.getResourceAsStream(resource); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); mapperParser.parse(); } else if (resource == null && url != null && mapperClass == null) { ErrorContext.instance().resource(url); InputStream inputStream = Resources.getUrlAsStream(url); XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); mapperParser.parse(); } else if (resource == null && url == null && mapperClass != null) { Class<?> mapperInterface = Resources.classForName(mapperClass); configuration.addMapper(mapperInterface); } else { throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); } } } } }
其中MapperRegistry對(duì)象中存放所有MapperProxyFactory對(duì)象的容器是一個(gè)hashmap
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>(); public <T> void addMapper(Class<T> type) { if (type.isInterface()) { if (hasMapper(type)) { throw new BindingException("Type " + type + " is already known to the MapperRegistry."); } boolean loadCompleted = false; try { knownMappers.put(type, new MapperProxyFactory<T>(type)); // It's important that the type is added before the parser is run // otherwise the binding may automatically be attempted by the // mapper parser. If the type is already known, it won't try. MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } }
在構(gòu)造factory的最后返回了一個(gè)DefaultSqlSessionFactory對(duì)象,并將創(chuàng)建好的Configuration對(duì)象當(dāng)作參數(shù)傳給了該對(duì)象,成為了他的成員變量。
第二步得到SqlSession對(duì)象
SqlSession session = sqlSessionFactory.openSession();
跟蹤獲取session的過(guò)程
@Override public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); final Executor executor = configuration.newExecutor(tx, execType); return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
最終得到的DefaultSqlSession中包含兩個(gè)重要對(duì)象,一個(gè)是從configuration里來(lái)的Enviroment,另外一個(gè)是包含TransactionFactroy對(duì)象的Executor對(duì)象。
其中獲得Executor對(duì)象的函數(shù)如下
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
這其中應(yīng)用的包裝模式(將SimpleExecutor對(duì)象包裝成CachingExecutor)和責(zé)任鏈模式(給CachingExecutro對(duì)象裝配上plugin)
第三步 根據(jù)傳入的接口信息生成動(dòng)態(tài)代理
TestMapper mapper=session.getMapper(TestMapper.class);
繼續(xù)跟蹤代碼
@Override public <T> T getMapper(Class<T> type) { return configuration.<T>getMapper(type, this); } public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
@SuppressWarnings("unchecked") public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } } public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); }
@SuppressWarnings("unchecked") protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }
大致流程就是先從configuration中找mapperRegistry,再?gòu)膍apperRegistry中找當(dāng)初存放mapperfactory的hashmap,再?gòu)倪@個(gè)hashmap中找到相應(yīng)的mapperfactory,最后mapperfactory構(gòu)造了一個(gè)mapperproxy對(duì)象,并調(diào)用了java的Proxy類,構(gòu)造了一個(gè)動(dòng)態(tài)代理對(duì)象的實(shí)例。
看一下MapperProxy的代碼
/** * Copyright 2009-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ibatis.binding; import java.io.Serializable; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Map; import org.apache.ibatis.reflection.ExceptionUtil; import org.apache.ibatis.session.SqlSession; /** * @author Clinton Begin * @author Eduardo Macarron */ public class MapperProxy<T> implements InvocationHandler, Serializable { private static final long serialVersionUID = -6424540398559729838L; private final SqlSession sqlSession; private final Class<T> mapperInterface; private final Map<Method, MapperMethod> methodCache; public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) { this.sqlSession = sqlSession; this.mapperInterface = mapperInterface; this.methodCache = methodCache; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { try { return method.invoke(this, args); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); } private MapperMethod cachedMapperMethod(Method method) { MapperMethod mapperMethod = methodCache.get(method); if (mapperMethod == null) { mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()); methodCache.put(method, mapperMethod); } return mapperMethod; } }
該class實(shí)現(xiàn)了InvocationHandler接口,我們知道java中的動(dòng)態(tài)代理模式需要代理class來(lái)實(shí)現(xiàn)InvocationHandler接口,
而最后動(dòng)態(tài)得到的實(shí)例調(diào)用函數(shù)實(shí)際上調(diào)用的是代理對(duì)象的invoke的函數(shù),所以我們第四步的入口就在這個(gè)class里
第四步 調(diào)用接口函數(shù)test,執(zhí)行sql語(yǔ)句
由代理對(duì)象中的inove函數(shù)知道,函數(shù)最后執(zhí)行的其實(shí)是MapperMethod類的execute函數(shù)。
一路跟蹤代碼到SimpleExecutor下的doQuery函數(shù)中
@Override public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } }
此處生成了一個(gè)StatementHandler對(duì)象和一個(gè)Statement對(duì)象
先看看Statement的生成過(guò)程
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); stmt = handler.prepare(connection, transaction.getTimeout()); handler.parameterize(stmt); return stmt; }
先生成Connection對(duì)象 ,用的也是代理模式
protected Connection getConnection(Log statementLog) throws SQLException { Connection connection = transaction.getConnection(); if (statementLog.isDebugEnabled()) { return ConnectionLogger.newInstance(connection, statementLog, queryStack); } else { return connection; } } public static Connection newInstance(Connection conn, Log statementLog, int queryStack) { InvocationHandler handler = new ConnectionLogger(conn, statementLog, queryStack); ClassLoader cl = Connection.class.getClassLoader(); return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler); }
然后生成preparestatement
@Override public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(boundSql.getSql()); Statement statement = null; try { statement = instantiateStatement(connection); setStatementTimeout(statement, transactionTimeout); setFetchSize(statement); return statement; } catch (SQLException e) { closeStatement(statement); throw e; } catch (Exception e) { closeStatement(statement); throw new ExecutorException("Error preparing statement. Cause: " + e, e); } }
@Override protected Statement instantiateStatement(Connection connection) throws SQLException { String sql = boundSql.getSql(); if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { String[] keyColumnNames = mappedStatement.getKeyColumns(); if (keyColumnNames == null) { return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); } else { return connection.prepareStatement(sql, keyColumnNames); } } else if (mappedStatement.getResultSetType() != null) { return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } else { return connection.prepareStatement(sql); } }
最后調(diào)用了connec tion的prepareStatement函數(shù),而因?yàn)閏onnection其實(shí)是一個(gè)代理對(duì)象,他實(shí)際調(diào)用的函數(shù)是
@Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, params); } if ("prepareStatement".equals(method.getName())) { if (isDebugEnabled()) { debug(" Preparing: " + removeBreakingWhitespace((String) params[0]), true); } PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params); //實(shí)際調(diào)用創(chuàng)建prepareedstatement對(duì)象的地方 stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack); return stmt; } else if ("prepareCall".equals(method.getName())) { if (isDebugEnabled()) { debug(" Preparing: " + removeBreakingWhitespace((String) params[0]), true); } PreparedStatement stmt = (PreparedStatement) method.invoke(connection, params); stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack); return stmt; } else if ("createStatement".equals(method.getName())) { Statement stmt = (Statement) method.invoke(connection, params); stmt = StatementLogger.newInstance(stmt, statementLog, queryStack); return stmt; } else { return method.invoke(connection, params); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } public static PreparedStatement newInstance(PreparedStatement stmt, Log statementLog, int queryStack) { InvocationHandler handler = new PreparedStatementLogger(stmt, statementLog, queryStack); ClassLoader cl = PreparedStatement.class.getClassLoader(); return (PreparedStatement) Proxy.newProxyInstance(cl, new Class[]{PreparedStatement.class, CallableStatement.class}, handler); }
發(fā)現(xiàn)原來(lái)這個(gè)pareparedStatement對(duì)象還是個(gè)代理對(duì)象
繼續(xù)跟蹤代碼
@Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.<E> handleResultSets(ps); }
調(diào)用了之前生成的preparedStatement對(duì)象的execute函數(shù),其實(shí)也就是代理對(duì)象的inovke函數(shù)
@Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, params); } if (EXECUTE_METHODS.contains(method.getName())) { if (isDebugEnabled()) { debug("Parameters: " + getParameterValueString(), true); } clearColumnInfo(); if ("executeQuery".equals(method.getName())) { ResultSet rs = (ResultSet) method.invoke(statement, params); return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack); } else { return method.invoke(statement, params); } } else if (SET_METHODS.contains(method.getName())) { if ("setNull".equals(method.getName())) { setColumn(params[0], null); } else { setColumn(params[0], params[1]); } return method.invoke(statement, params); } else if ("getResultSet".equals(method.getName())) { ResultSet rs = (ResultSet) method.invoke(statement, params); return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack); } else if ("getUpdateCount".equals(method.getName())) { int updateCount = (Integer) method.invoke(statement, params); if (updateCount != -1) { debug(" Updates: " + updateCount, false); } return updateCount; } else { return method.invoke(statement, params); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }
此時(shí)sql語(yǔ)句執(zhí)行完成,之后是獲取結(jié)果集
第五步 獲取結(jié)果集
@Override public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); final List<Object> multipleResults = new ArrayList<Object>(); int resultSetCount = 0; ResultSetWrapper rsw = getFirstResultSet(stmt); List<ResultMap> resultMaps = mappedStatement.getResultMaps(); int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); while (rsw != null && resultMapCount > resultSetCount) { ResultMap resultMap = resultMaps.get(resultSetCount); handleResultSet(rsw, resultMap, multipleResults, null); rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } String[] resultSets = mappedStatement.getResultSets(); if (resultSets != null) { while (rsw != null && resultSetCount < resultSets.length) { ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]); if (parentMapping != null) { String nestedResultMapId = parentMapping.getNestedResultMapId(); ResultMap resultMap = configuration.getResultMap(nestedResultMapId); handleResultSet(rsw, resultMap, null, parentMapping); } rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } } return collapseSingleResultList(multipleResults); }
此處調(diào)用stmt.getResultSet(),然后他又進(jìn)了代理對(duì)象的invoke函數(shù)
@Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, params); } if (EXECUTE_METHODS.contains(method.getName())) { if (isDebugEnabled()) { debug("Parameters: " + getParameterValueString(), true); } clearColumnInfo(); if ("executeQuery".equals(method.getName())) { ResultSet rs = (ResultSet) method.invoke(statement, params); return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack); } else { return method.invoke(statement, params); } } else if (SET_METHODS.contains(method.getName())) { if ("setNull".equals(method.getName())) { setColumn(params[0], null); } else { setColumn(params[0], params[1]); } return method.invoke(statement, params); } else if ("getResultSet".equals(method.getName())) { ResultSet rs = (ResultSet) method.invoke(statement, params); return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack); } else if ("getUpdateCount".equals(method.getName())) { int updateCount = (Integer) method.invoke(statement, params); if (updateCount != -1) { debug(" Updates: " + updateCount, false); } return updateCount; } else { return method.invoke(statement, params); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } public static ResultSet newInstance(ResultSet rs, Log statementLog, int queryStack) { InvocationHandler handler = new ResultSetLogger(rs, statementLog, queryStack); ClassLoader cl = ResultSet.class.getClassLoader(); return (ResultSet) Proxy.newProxyInstance(cl, new Class[]{ResultSet.class}, handler); }
可以看到這還是一個(gè)代理模式,創(chuàng)建了一個(gè)用來(lái)獲取結(jié)果集的對(duì)象ResultSetLogger,看一下他的invoke函數(shù)
@Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, params); } Object o = method.invoke(rs, params); if ("next".equals(method.getName())) { if (((Boolean) o)) { rows++; if (isTraceEnabled()) { ResultSetMetaData rsmd = rs.getMetaData(); final int columnCount = rsmd.getColumnCount(); if (first) { first = false; printColumnHeaders(rsmd, columnCount); } printColumnValues(columnCount); } } else { debug(" Total: " + rows, false); } } clearColumnInfo(); return o; } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }
從ResultSetLogger對(duì)象遍歷出結(jié)果集還要經(jīng)過(guò)一步處理得到最終需要返回類型的結(jié)果集
第六步 封裝結(jié)果集
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException { try { if (parentMapping != null) { handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping); } else { if (resultHandler == null) { DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory); handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); multipleResults.add(defaultResultHandler.getResultList()); } else { handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); } } } finally { // issue #228 (close resultsets) closeResultSet(rsw.getResultSet()); } } public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { if (resultMap.hasNestedResultMaps()) { ensureNoRowBounds(); checkResultHandler(); handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } else { handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } } private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>(); skipRows(rsw.getResultSet(), rowBounds); while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null); Object rowValue = getRowValue(rsw, discriminatedResultMap); storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); } } private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException { final ResultLoaderMap lazyLoader = new ResultLoaderMap(); Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null); if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { final MetaObject metaObject = configuration.newMetaObject(resultObject); boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty(); if (shouldApplyAutomaticMappings(resultMap, false)) { foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues; foundValues = lazyLoader.size() > 0 || foundValues; resultObject = foundValues ? resultObject : null; return resultObject; } return resultObject; }
這一步最核心的代碼就是上面這個(gè)函數(shù),可以看到他是由configuration生成一個(gè)MetaObject,在通過(guò)applyAutomaticMappings函數(shù),將數(shù)據(jù)庫(kù)結(jié)果中相應(yīng)字段的值填充到MetaObject中,代碼如下
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException { List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix); boolean foundValues = false; if (autoMapping.size() > 0) { for (UnMappedColumnAutoMapping mapping : autoMapping) { final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column); if (value != null) { foundValues = true; } if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) { // gcode issue #377, call setter on nulls (value is not 'found') metaObject.setValue(mapping.property, value); } } } return foundValues; }
最后將得到的封裝好的對(duì)象放入一個(gè)list中返回結(jié)果,關(guān)閉數(shù)據(jù)庫(kù)連接,一次完整的sql語(yǔ)句執(zhí)行流程至此完結(jié) 。
以上這篇mybatis3使用@Select等注解實(shí)現(xiàn)增刪改查操作就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java?如何用二維數(shù)組創(chuàng)建空心菱形
這篇文章主要介紹了Java?如何用二維數(shù)組創(chuàng)建空心菱形,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03spring boot集成mongodb的增刪改查的示例代碼
這篇文章主要介紹了spring boot集成mongodb的增刪改查的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03java Iterator.remove()實(shí)例方法分析
在本篇文章里小編給大家整理了一篇關(guān)于java Iterator.remove()實(shí)例方法分析,有興趣的朋友們跟著學(xué)習(xí)下。2021-01-01詳解IDEA2020新建spring項(xiàng)目和c3p0連接池的創(chuàng)建和使用
C3P0是一個(gè)開(kāi)源的JDBC連接池,它實(shí)現(xiàn)了數(shù)據(jù)源和JNDI綁定,本文就使用Spring實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08SpringBoot 關(guān)于Feign的超時(shí)時(shí)間配置操作
這篇文章主要介紹了SpringBoot 關(guān)于Feign的超時(shí)時(shí)間配置操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09淺談java中字符串?dāng)?shù)組、字符串、整形之間的轉(zhuǎn)換
這篇文章主要介紹了淺談java中字符串?dāng)?shù)組、字符串、整形之間的轉(zhuǎn)換,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11