Built-in methods for Mapper
The model layer is the entity class, corresponding to the table of the database. The controller layer is a Servlet, which is mainly responsible for the control of the business module process, calling the service interface method, and in struts2 is Action. The Service layer mainly makes logical judgments, and the Dao layer is the data access layer, which connects with the database. As for Mapper, the mapper mapping file is used in the dao layer.
Here is a description of the built-in method of Mapper:
1. countByExample ===>Query the quantity according to the conditions
int countByExample(UserExample example); //The following is a complete case list. UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("joe"); int count = userDAO.countByExample(example); Equivalent to: select count(*) from user where username='joe'
2. deleteByExample ===>Delete multiple items according to the conditions
int deleteByExample(AccountExample example); //The following is a complete case UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("joe"); userDAO.deleteByExample(example); equivalent to: delete from user where username='joe' 3. deleteByPrimaryKey===>Delete a single item according to the conditions
int deleteByPrimaryKey(Integer id);userDAO.deleteByPrimaryKey(101);
Equivalent to:
delete from user where id=101
4. insert===>Insert data
int insert(Account record); //The following is the complete case User user = new User(); //user.setId(101); user.setUsername("test"); user.setPassword("123456") user.setEmail("[email protected]"); userDAO.insert(user);Equivalent to:
insert into user(ID,username,password,email) values(101,'test','123456','[email protected]');
5. insertSelective===>Insert data
int insertSelective(Account record);
6. selectByExample===>Query data based on conditions
List<Account> selectByExample(AccountExample example); //The following is a complete case UserExample example = new UserExample();Criteria criteria = example.createCriteria();criteria.andUsernameEqualTo("joe");criteria.andUsernameIsNull();example.setOrderByClause("username asc,email desc");List<?>list = userDAO.selectByExample(example);equivalent: select * from user where username = 'joe' and username is null order by username asc,email desc //Note: The file UserExample.java generated by iBator contains a static internal class Criteria. There are many methods in Criteria, mainly to define the query conditions after SQL statement where.7. selectByPrimaryKey===>Query data based on the primary key
Account selectByPrimaryKey(Integer id);//Equivalent to select * from user where id = variable id
8. updateByExampleSelective===>Update fields with values not null according to conditions
int updateByExampleSelective(@Param("record") Account record, @Param("example") AccountExample example); //The following is a complete case list UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("joe"); User user = new User(); user.setPassword("123"); userDAO.updateByPrimaryKeySelective(user,example); equivalent to: update user set password='123' where username='joe'
9. updateByExampleSelective===>Update by condition
int updateByExample(@Param("record") Account record, @Param("example") AccountExample example);10. updateByPrimaryKeySelective===>Update according to conditions
int updateByPrimaryKeySelective(Account record);//The following is a complete case User user = new User();user.setId(101);user.setPassword("joe");userDAO.updateByPrimaryKeySelective(user);Equivalent to:
update user set password='joe' where id=101
int updateByPrimaryKeySelective(Account record); //The following is a complete case User user = new User();user.setId(101);user.setPassword("joe");userDAO.updateByPrimaryKeySelective(user);Equivalent to: update user set password='joe' where id=101
11. updateByPrimaryKey===>Press the primary key to update
int updateByPrimaryKey(Account record);//The following is a complete case User user =new User(); user.setId(101); user.setUsername("joe"); user.setPassword("joe"); user.setEmail("[email protected]"); userDAO.updateByPrimaryKey(user);Equivalent to:
update user set username='joe',password='joe',email='[email protected]' where id=101
int updateByPrimaryKey(Account record); //The following is a complete case User user =new User(); user.setId(101); user.setUsername("joe"); user.setPassword("joe"); user.setEmail("[email protected]"); userDAO.updateByPrimaryKey(user);Equivalent to:
update user set username='joe',password='joe',email='[email protected]' where id=101
Parsing the mapper's xml configuration file
Let's take a look at how mybatis reads the mapper's XML configuration file and parses the SQL statements in it.
We still remember configuring the sqlSessionFactory like this:
<bean id="sqlSessionFactory"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:configuration.xml"></property> <property name="mapperLocations" value="classpath:com/xxx/mybatis/mapper/*.xml"/> <property name="typeAliasesPackage" value="com.tiantian.mybatis.model" /> </bean>
Here is a mapperLocations property, which is an expression. The sqlSessionFactory will read all xml format files below the package com.xxx.mybaits.mapper according to this expression. So how do you read the configuration file based on this attribute?
The answer is in the buildSqlSessionFactory method in the SqlSessionFactoryBean class:
if (!isEmpty(this.mapperLocations)) { for (Resource mapperLocation : this.mapperLocations) { if (mapperLocation == null) { continue; } try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), configuration, mapperLocation.toString(), configuration.getSqlFragments()); xmlMapperBuilder.parse(); } catch (Exception e) { throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e); } finally { ErrorContext.instance().reset(); } if (logger.isDebugEnabled()) { logger.debug("Parsed mapper file: '" + mapperLocation + "'"); } } }mybatis uses an instance of the XMLMapperBuilder class to parse mapper configuration files.
public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments) { this(new XPathParser(reader, true, configuration.getVariables(), new XMLMapperEntityResolver()), configuration, resource, sqlFragments); } private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) { super(configuration); this.builderAssistant = new MapperBuilderAssistant(configuration, resource); this.parser = parser; this.sqlFragments = sqlFragments; this.resource = resource; }Then the system calls the parse method of xmlMapperBuilder to parse the mapper.
public void parse() { //If the configuration object has not loaded the xml configuration file (avoiding duplicate loading, it is actually to confirm whether the properties and content of the mapper node have been parsed, //Preparing for parsing its child nodes such as cache, sql, select, resultMap, parameterMap, etc.), //Parse the mapper node from the input stream, and then set the status of the resource to loaded if (!configuration.isResourceLoaded(resource)) { configurationElement(parser.evalNode("/mapper")); configuration.addLoadedResource(resource); bindMapperForNamespace(); } //Parse the <resultMap> node that has not been processed when processing resultMap in the configurationElement function. parsePendingResultMaps(); //Parse the <cache> node that does not exist when processing cache-ref in the configurationElement function (this will happen if cache-ref is loaded before the cache node it points to) parsePendingChacheRefs(); //Same as above, if cache is not loaded, an exception will also be thrown when processing statement parsePendingStatements(); }The process of mybatis parsing the mapper's xml file is already very obvious. Let's take a look at how it parses the mapper:
private void configurationElement(XNode context) { try { //Get the namespace attribute of the mapper node String namespace = context.getStringAttribute("namespace"); if (namespace.equals("")) { throw new BuilderException("Mapper's namespace cannot be empty"); } //Set the current namespace builderAssistant.setCurrentNamespace(namespace); //Parse the mapper's <cache-ref> node cacheRefElement(context.evalNode("cache-ref")); //Parse the mapper's <cache> node cacheElement(context.evalNode("cache")); //Parse the mapper's <parameterMap> node parameterMapElement(context.evalNodes("/mapper/parameterMap")); //Parse the mapper's <resultMap> node resultMapElements(context.evalNodes("/mapper/resultMap")); //Parse the mapper's <sql> node sqlElement(context.evalNodes("/mapper/sql")); //Use XMLStatementBuilder object to parse the mapper's <select>, <insert>, <update>, <delete> nodes, //mybaits will use the MappedStatement.Builder class to build a MappedStatement object, //So an sql in mybaits corresponds to a MappedStatement buildStatementFromContext(context.evalNodes("select|insert|update|delete")); } catch (Exception e) { throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e); } }The configurationElement function parses almost all child nodes in the mapper node. At this point, mybaits parses all nodes in the mapper and adds them to the Configuration object for the SQLSessionFactory object to be used at any time. Here we need to add some explanation on how mybaits uses the parseStatementNode function of the object of the XMLStatementBuilder class to borrow the addMappedStatement of the MapperBuilderAssistant object builderAssistant to parse the MappedStatement and associate it to the Configuration class object:
public void parseStatementNode() { //ID attribute String id = context.getStringAttribute("id"); //databaseId attribute String databaseId = context.getStringAttribute("databaseId"); if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) { return; } //fetchSize attribute Integer fetchSize = context.getIntAttribute("fetchSize"); //timeout attribute Integer timeout = context.getIntAttribute("timeout"); //parameterMap attribute String parameterMap = context.getStringAttribute("parameterMap"); //parameterType attribute String parameterType = context.getStringAttribute("parameterType"); Class<?> parameterTypeClass = resolveClass(parameterType); //resultMap attribute String resultMap = context.getStringAttribute("resultMap"); //resultType attribute String resultType = context.getStringAttribute("resultType"); //lang attribute String lang = context.getStringAttribute("lang"); LanguageDriver langDriver = getLanguageDriver(lang); Class<?> resultTypeClass = resolveClass(resultType); //resultSetType attribute String resultSetType = context.getStringAttribute("resultSetType"); StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString())); ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType); String nodeName = context.getNode().getNodeName(); SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH)); //Is it a <select> node boolean isSelect = sqlCommandType == SqlCommandType.SELECT; //flushCache attribute boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect); //useCache attribute boolean useCache = context.getBooleanAttribute("useCache", isSelect); //resultOrdered attribute boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false); //Include Fragments before parsing XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant); includeParser.applyIncludes(context.getNode()); // Parse selectKey after include and remove them. processSelectKeyNodes(id, parameterTypeClass, langDriver); // Parse the SQL (pre: <selectKey> and <include> were parsed and removed) SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass); //resultSets property String resultSets = context.getStringAttribute("resultSets"); //keyProperty property String keyProperty = context.getStringAttribute("keyProperty"); //keyColumn property String keyColumn = context.getStringAttribute("keyColumn"); KeyGenerator keyGenerator; String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX; keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true); if (configuration.hasKeyGenerator(keyStatementId)) { keyGenerator = configuration.getKeyGenerator(keyStatementId); } else { //useGeneratedKeys attribute keyGenerator = context.getBooleanAttribute("useGeneratedKeys", configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType)) ? new Jdbc3KeyGenerator() : new NoKeyGenerator(); } builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets); } From the above code, we can see that mybaits uses XPath to parse the mapper configuration file and then creates the resultMap, parameterMap, cache, statement and other nodes in it using the associated builder and associates the obtained object into the configuration object. This configuration object can be obtained from sqlSession, which explains the problem of how mybaits gets the mapper and executes the SQL statements in it when we use sqlSession to operate the database.