preface

Yesterday, I saw this interview question from Ali in an interview book:

How to establish the relationship between Dao interface in Mybatis and SQL in XML file? Wouldn’t it be a conflict if there were two XML files associated with the DAO?

If you read my previous blog about Mybatis source analysis, I believe you can give a good answer.

However, given the length of this series of articles, and the focus is on the interpretation of the source part, so THE author would like to address this problem, and comb through the whole process.

This article with the following articles, edible better.

XML parsing and annotation support

How is the DAO interface invoked

The execution process of SQL statements

Parsing XML

First, when Mybatis initializes SqlSessionFactoryBean, it finds the mapperLocations path to parse all the XML files in it. We’ll focus on two parts here.

1. Create SqlSource

Mybatis wraps each SQL tag into an SqlSource object. Then according to the different SQL statements, it is divided into dynamic SQL and static SQL. Static SQL contains a String SQL statement. Dynamic SQL is composed of sqlNodes.

Suppose we have an SQL like this:

<select id="getUserById" resultType="user">
	select * from user 
	<where>
		<if test="uid! =null">
			and uid=#{uid}
		</if>
	</where>
</select>	
Copy the code

The corresponding SqlSource object should look like this:

2. Create MappedStatement

Each SQL tag in an XML file corresponds to a MappedStatement object, and there are two attributes that are important.

  • id

The ID of the fully qualified class name plus the method name.

  • sqlSource

The SqlSource object corresponding to the current SQL tag.

After creating the MappedStatement object, cache it in Configuration#mappedStatements.

The Configuration object, as we know, is the big manager in Mybatis. Basically all the Configuration information is maintained here. After all the XML has been parsed, the Configuration contains all the SQL information.

At this point, the XML is parsed. If you’re smart enough to look at the picture above, you might have an idea. Mybatis = Mybatis = Mybatis = Mybatis = Mybatis = Mybatis = Mybatis = Mybatis = Mybatis = Mybatis

Dao interface proxy

Our Dao interface does not implement a class, so how does it end up executing into our SQL statement when we call it?

First, in our Spring configuration file, we typically configure this:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="com.viewscenes.netsupervisor.dao" />
	<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
Copy the code

Or if your project is based on SpringBoot, you’ve probably seen this before: @mapperscan (“com.xxx.dao”)

They do the same thing. Register all classes in the package path into the Spring Bean and set their beanClass to MapperFactoryBean. Interestingly, MapperFactoryBean implements the FactoryBean interface, commonly known as factory Beans. So, when we inject the Dao interface via @AutoWired, the object returned is the getObject() method object in the MapperFactoryBean factory Bean.

So what does this approach do?

In simple terms, it is the JDK dynamic proxy that returns a PROXY object for the Dao interface. The handler of this proxy object is the MapperProxy object. So, when we inject the Dao interface via @AutoWired, we inject this proxy object, and when we call the Dao interface method, we call the MapperProxy object invoke method.

Spring factoryBeans and JDK dynamic proxies are a good place to start

A friend once asked this question:

Does Mapper still use proxies for implemented DAO interfaces?

The answer is yes, as long as you configure itMapperScan, it will scan and generate the proxy. However, if your DAO interface has an implementation class, and that implementation class is also a Spring Bean, it depends on where you areAutowiredTo inject which one.

What exactly does that mean? We come to an example.

If we give the userDao an implementation class and register it with Spring.

@Component
public class UserDaoImpl implements UserDao{
	public List<User> getUserList(Map<String,Object> map){
		returnnew ArrayList<User>(); }}Copy the code

We then inject the userDao in the Service method. Guess what?

@Service
public class UserServiceImpl implements UserService{

	@Autowired
	UserMapper userDao1;

	public List<User> getUserList(Map<String,Object> map) {
		returnuserDao1.getUserList(map); }}Copy the code

As you might have guessed, yes, it will launch an error. Because at the time of injection, two instance objects of UserMapper were found. Log is this: No qualifying bean of type [com.viewscenes.net supervisor. Dao. UserDao] is defined: expected single matching bean but found 2: userDaoImpl,userDao

Of course, maybe we’re not naming things properly. In fact, we can inject it by name, like this: @autoWired UserMapper userDao; Or @autoWired UserMapper userDaoImpl; Or annotate one of your beans with @primary.

For details, see my article: Getting to the bottom of Autowiring and Autowired in Spring

Said said may be far away, we continue to return to Mybatis. So, so far, we also have a proxy implementation through the Dao interface, so we can execute the methods inside it.

Three, execute,

As mentioned above, when we call the Dao interface method, we actually call the invoke method of the proxy object. In this case, what is actually called is the stuff inside the SqlSession.

public class DefaultSqlSession implements SqlSession {

	public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
		try {
			MappedStatement ms = configuration.getMappedStatement(statement);
			returnexecutor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); }}}Copy the code

Seeing the code above, we’re on to something. It fetches the MappedStatement object through the statement fully qualified type + method name, executes the specific SQL through the Executor and returns it.

Four,

Now, let’s go back to the question we asked at the beginning, and maybe you can answer it better. At the same time, I think the interviewer will be very satisfied if you cover the following key words.

  • SqlSource and dynamic label SqlNode
  • MappedStatement object
  • Spring factory beans and dynamic proxies
  • SqlSession and the executor

So, to answer the second question: if there are two XML files that have a relationship with the Dao, isn’t that a conflict?

The obvious answer is to keep namespace+ ID unique, regardless of how many XML relationships you have with daOs.