Recently, I found that some project Mybatis is developed based on annotations while MY personal habit is to develop based on XML files.
For mybatis annotation development principle understanding is not enough, then read part of the source code, write this article. This paper mainly introduces two forms and three writing methods of mybatis development. There is a little blind thinking, introduced a SAO code, there is a pit.
Original is not easy, thank you for reading, thank you for your attention, thank you for liking, thank you for forwarding.
Drought cavity be out of tune
Hello, I’m Why. As usual, before we start our tech talk, let’s talk about something else.
Last week I wrote this article, “Is the third edition of this book worth buying?” Unexpectedly, Mr. Zhou Zhiming, the author of “In-depth understanding of Java VIRTUAL machine”, saw it and gave me a message of appreciation and said to me: the author expressed his gratitude, sincerely.
To be honest, I was shocked when I saw the praise. There is a feeling of intersection with the great god.
In fact, the publisher came to me with this article last week and said to give me a copy of the third edition and let me read it and write about it.
Well, that’s exactly what I was planning on doing before they found me.
I’m not trying to get a few books from a White House publisher, but I’ve been working on this article since I decided to buy the third edition at the end of last year.
By chance, he completed his plan and got several books from the publishing house. Through the publishing house, he hooked up with the author of this book and not only got the author’s appreciation but also got a signed edition.
Oh, this crazy, fucked-up life.
So what have I learned from all this writing?
To be honest, I don’t make much money by writing articles. But what I got was the opportunity to walk with a group of like-minded original writers, the comments and praise from readers after reading the articles, and the occasional interaction with a few industry bigwigs.
That’s all.
All right, back to the article.
Two forms, three ways of writing it
Recently, I found that mybatis in some projects of the company is developed based on annotations. My personal habit is to develop based on XML files.
Therefore, I don’t know much about the principle of development based on annotations, so I went to look at the relevant source code and formed this article.
This paper mainly introduces two forms and three writing methods based on Mybatis development.
Two of these forms refer to:
1. Based on XML files.
2. Annotation-based development.
Three ways to write annotations means that in addition to XML, there are two different ways to write annotations, and their implementation principles are slightly different. Take Select statements for example, there are two annotation @select and @selectProvider.
Demo sample
First, a demonstration example to give you an intuitive feeling:
First, we have a user table that contains these fields and this data:
Then we create an interface class to query the user’s age in three ways, as follows:
The xmlQueryAgeByName method uses XML to query the user’s age as follows:
The annotationQueryAgeByName method uses the @select annotation to query the user’s age.
The classQueryAgeByName method uses the @selectProvider annotation to query the age of the user. A method field corresponding to a method in the class:
UserInfoSql class is as follows:
Then, we have another test case that tests all three methods:
The final output is as follows:
XmlQueryAgeByName whyAge = 18 annotationQueryAgeByName whyAge = 18 classQueryAgeByName whyAge = 18 Copies codeCopy the code
The test case is done. It’s a very simple use case.
I am based on this case to analyze the source code, before the analysis, in fact, some experience of the elder brother can also see, let’s first put aside the conventional XML file form not to talk about.
Based on the @select annotation interface, the SQL is inside the annotation, so we just need to reflect the SQL inside the annotation and analyze it.
The @selectProvider annotation interface, SQL is in a class method, but the annotation tells you which class method, so it must be based on reflection to fetch the SQL in the method.
Now, we’re going to test that.
All right, get ready to go.
Caution beg a certificate
About Mybatis, I wrote this article before “I am very happy that I stepped on a pit in the process of using Mybatis”, which mentioned a reverse screening method. Those who are interested can go and have a look.
Let’s stick to a routine analysis in this article. This article analyzes the source code for mybatis 3.4.0 version.
First, let me ask you a question. How does SpringBoot load Mybatis?
The “Spring. factories” files in the meta-INF directory of mybatis-spring-boot-autoconfigure-x.x.x.jar can be loaded.
So, the following sqlSessionFactory method is our entry point:
You have found the entry point, you can directly add a breakpoint here to start debugging.
I know it’s just the beginning, but some readers may think it’s over the top. But it doesn’t matter, keep watching, I’m just showing you where the entrance is.
Since the debug process is not the focus of the text, it will not be covered here. We see this method when we debug:
org.apache.ibatis.builder.xml.XMLMapperBuilder#parse
Line 92 of this method is our XML content:
Then go crazy parsing the XML file in the following method:
org.apache.ibatis.builder.xml.XMLStatementBuilder#parseStatementNode
You can open the image to see the larger image. In Debug mode, you can see some output:
In line 94 of the source code above, obtaining the SqlSource is critical, so take a closer look. Here we call this method:
org.apache.ibatis.scripting.xmltags.XMLLanguageDriver#createSqlSource(org.apache.ibatis.session.Configuration, org.apache.ibatis.parsing.XNode, java.lang.Class<? >)
Then, in line 52 of the following method, peel out the entire SQL:
org.apache.ibatis.scripting.xmltags.XMLScriptBuilder#parseScriptNode
The above is the process of obtaining the raw SQL statement in XML form (variables, conditional expressions have not been replaced, cannot be directly executed SQL). It is not the focus of this article, but a simple analysis will do.
This is the method we care about when parsing annotations:
org.apache.ibatis.builder.annotation.MapperAnnotationBuilder#parse
In this method, we loop through methods in the Mapper class:
Next, you will encounter this method:
org.apache.ibatis.builder.annotation.MapperAnnotationBuilder#getSqlSourceFromAnnotations
When looped to the annotationQueryAgeByName method, some of the key parameters of the following method are as follows:
SqlAnnotationType = Select; sqlAnnotationType = Select;
So we go to the following if branch and run to line 435 to get the SQL statement on the @SELECT annotation by reflection:
Further down, through line 436, we can go to this method:
org.apache.ibatis.scripting.xmltags.XMLLanguageDriver#createSqlSource(org.apache.ibatis.session.Configuration, java.lang.String, java.lang.Class<? >)
This method checks if script (SQL) starts with a script script, and if so, follows the same parsing logic as XML:
When I first saw this place, it suddenly dawned on me that @Select was essentially an XML file. It’s just a different presentation.
One of my previous problems, or misconceptions, was solved.
Here, by the way, I send you a classic learning materials, I used in university and work of the classic e-book library (including data structure, operating system, C++/C, network classics, front-end programming classics, Java related, programmer cognition, career development), interview and job summary are packed here.
Computer Classics required reading list (including download methods)
I previously thought that the @select approach would only support simple SQL writing and would not support some requirements such as nulling. (Because I am not familiar with the annotation development of Mybatis)
For example, in an XML file, write:
<when test='startPage ! =null and pageSize ! = null '> LIMIT #{startPage},#{pageSize} </when> Copy codeCopy the code
It’s just that the way it’s written is, well, not very elegant.
Don’t just annotate for the sake of annotating; it’s obviously better to just use XML in this case.
Mybatis will use reflection to get the SQL in the annotation when it is developed based on @select annotation. These SQL needs some complicated functions, such as determining whether the condition is empty or not, it can be wrapped with script tags. The writing is the same as developing in XML.
Next, let’s look at what the @selectProvider method looks like.
Again, in the same way, but in a different direction:
The sqlProviderAnnotation at this point contains the following:
Then go to the new ProviderSqlSource object:
In this method, you get the specific method on the annotation that provides the original SQL statement.
Notice the providerMethod object in the red box, which will be used later to get the actual executed SQL statement.
Also, we can see that the ProviderSqlSource is the implementation class for the SqlSource.
So, whether it’s XML or annotations, you eventually need to get an SqlSource object.
In this article’s sample code, XML and @SELECT generate RawSqlSource.
The @selectProvider generates the ProviderSqlSource. They put different things in them.
The sqlSource variable in RawSqlSource (type StaticSqlSource) contains the original SQL statement retrieved from THE XML or @SELECT annotation (but the variable has not been replaced yet). Because the program does not know what the value of a variable is, if there are some conditional expressions).
In the ProviderSqlSource, as we said earlier, we put the @SelectProvider annotation that provides the method that provides the SQL statement, just the method, not the statement.
All the previous analysis is before our method is actually executed, and then, it will debug to our test case, because only our test case has real input parameters, mybatis can execute the final SQL statement according to the input parameters.
So, the next step is to find the place where the SQL statement is actually generated, which can be echoed in the previous article “very happy, I stepped on a pit in the process of using Mybatis” in the reverse investigation method.
If we go to getBoundSql, we can see line 292, which is the boundSql object obtained from the getBoundSql method of the sqlSource:
org.apache.ibatis.scripting.xmltags.DynamicSqlSource#getBoundSql
Isn’t that what this is all about? See the sqlSource again.
So, next, let’s take a look at these two methods:
org.apache.ibatis.builder.StaticSqlSource#getBoundSql Copying code org. Apache. Ibatis. Builder. The annotation. ProviderSqlSource# getBoundSqlCopy the code
Let’s take a look at the StaticSqlSource implementation:
Some of the key parameters are as follows:
First of all, SQL variables, which is a SQL statement to be processed, we have analyzed before, in the process of program startup, why not replace here?
Because I don’t know what to change it to.
At the same time to share a system of Java books, suitable for small white to god of all kinds of needs are sorted out.
Java Resource pack: Java Getting Started to Master The most comprehensive resource pack including interview (including download method) Super career & Cognition core book list: 2021, Nuggets the most core book list
Do you think it will be replaced here?
Still not. UserName = ‘why’; userName = ‘why’; userName = ‘why’;
But what if we pass in “why or 1=1”?
I’m sure you’ll see what this is all about, SQL injection.
By the way, if you want to see SQL injection, just go to DynamicSqlSource and replace # with $in XML. If you’re interested, try it.
I’m just going to give you a snapshot here, take a look:
All right, let’s pick up where we left off.
Continuing debug will go to this method:
org.apache.ibatis.executor.SimpleExecutor#doQuery
PrepareStatement (); prepareStatement (); prepareStatement (); prepareStatement ();
Finally, the actual query operation is performed to process the return value.
Moving on to the implementation of ProviderSqlSource, notice the part of the branch judgment I circled:
It’s just a matter of determining how many parameters you need to pass in a reflection method call. This method is eventually called to get the SQL statement:
Let’s see what the providerMethod and SQL variables are at this point:
Okay, so where did this providerMethod come from? We just analyzed that.
For the new ProviderSqlSource object, I specifically said: “Notice the providerMethod object in the red box, which will be used later when we get the SQL statement that is actually executed.”
That’s where it comes in.
There you go. There you go again.
At this point, we have the original SQL statement and parameters, and this scenario is exactly the same as the one we just analyzed, so the logic behind is the same, and the code is reused:
Go to line 98, which is the following method we analyzed earlier:
org.apache.ibatis.builder.SqlSourceBuilder#parse
In this method, a StaticSqlSource object is returned:
Again, the process is the same.
If you are interested, you can use the @selectProvider annotation to write a method in the class object:
Ok, so that’s the end of our argument. I found this thing, which was really explained in a few minutes in the video, was a little difficult to describe. Did you force me to be the UP leader?
I don’t know if you understand mybatis, if you don’t know much about mybatis friends may look a little bit difficult, but it doesn’t matter, you just take this article as a guide, and then make a Demo to run, play.
Individual thinking
Actually, a thought came to me when I was writing this article.
Why should Mybatis support annotations?
Of course, as we all know, annotation-based development is the trend, which simplifies a lot for us.
SpringBoot, in particular, was the golden age of annotation development.
Back in my early days, most of the time developing an SSM project was spent configuring XML files.
I envy the fact that I’m young enough to have never really experienced (perhaps built and played with) the fear of being dominated by XML configuration.
In the AGE of XML, everyone is sticky. Now that I’m developing based on annotations, a lot of things have been simplified and I’m able to build small projects that can run easily.
So, annotation-based development in general is a very elegant, very good, and well worth promoting.
Why say in general?
Because of my personal prejudice, mybatis without XML file is soulless for mybatis framework.
Of course, if you have all the functionality that a simple SQL statement can do, you can use annotations. But this case, I think is still in the minority.
Again, you can use annotations to do everything an XML file can do. But I don’t think it’s very elegant.
So, I think a compromise is that simple SQL can be developed with annotations, whereas SQL with requirements such as conditional judgment classes should still be written in XML files.
Don’t abandon XML altogether to embrace annotations.
Remember, when the XML era moved to the annotated era, there was another annotation that was used a lot.
Some say it’s a product of a transitional era, but to me it’s a perfect example of agreeing to disagree.
This note, on the full embodiment of the recent very popular saying:
The gentleman united with the United States, and different.
Of course these are some of my shallow personal views generated in the process of writing this article. There is no reference significance.
SAO code
In addition, to share a I think mybatis code bar.
The code is very simple and clear, a long time ago when I first looked at mybatis source code is a little “SAO”, left a deep impact on me:
org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(java.lang.String, java.lang.Object)
SelectOne method:
This method still calls the selectList method, but makes a judgment on the returned collection that if it is 1, it is indeed a selectOne, and if it is greater than 1, it throws an exception.
To be honest, if I were to implement this feature, I would not immediately think of this method, I would honestly write the function and then judge the return value. I might not find out until I’m done. Well, you can reuse this code with the selectList method, and then extract it, and it looks like this.
I remember the interview a long time ago, the interviewer asked me which paragraph of the source code has a profound impact, which I mentioned this method.
Anyway, personally, I think it’s great.
Pay attention to the pit
And then there’s the pothole we stomped on, which led to an emergency ramp.
Or take the example in the text to illustrate:
If we change the return value from Integer to int:
Using this test case will still normally query the result:
But what if we query the age of a person who doesn’t exist in the database? Like this:
An error like this is thrown:
Find the corresponding source code, we can see:
When the return value is null, but the return value type on the method is not one of the wrapper types or void, an exception is thrown.
Look at this method, which is native:
java.lang.Class#isPrimitive
Why do you think Mybatis made such a judgment for you?
If null is returned, the auto-unpacking will throw a null pointer.
Even though Mybatis blocked it for us, I still stepped on a hole perfectly and wrote a null pointer exception.
The code looks like this, but I still use Integer to receive:
But the return value of the interface call is written like this:
See? No problem. Null pointer. There’s no running.
One last word (for attention)
The potential of people is really huge, and I don’t know if I could get this article done this week without pushing myself.
Recently, I came back a little late in the evening, so I generally had no time to write articles in the evening of the week.
Chengdu has become hot recently, and SOMETIMES I still need a nap in summer to keep working in the afternoon. I don’t need a lunch break in other seasons, so now I have little time to write articles at noon.
By the way, even with this post, I’ve posted 48 original articles for 39 weeks in a row.
Oh, I’m such a bull.
Zhou Geng author of pain and happiness, you can not imagine:
Give me a thumbs up, zhou is more tired, don’t fuck me, need some positive feedback.
Lack of knowledge, inevitably there will be loopholes, if you found the wrong place, because this number has no message function, please also point out the message in the background, I modify it.
I myself liver six copies of PDF < about Java entry to god >, the whole network spread more than 10W +, search “code farmers attack” after paying attention to the public number, in the background reply PDF, get all PDF
Six PDF links
Welcome to follow my official account: [Code farming Attack], share Python, Java, big data, machine learning, artificial intelligence and other technologies, pay attention to code farming technology improvement • career breakthrough • thinking transition, 100,000 + code farming growth charge first stop, accompany you have a dream to grow together.