SoFunction
Updated on 2025-04-04

Spring Boot Mybatis++ 2025 Detailed explanation

Structure

this blog introduce 3 ways using mybatis

  • based on annotationed SQL and Query interfaces : suppored by MyBatis framework
  • based on Query Wrapper : supported by MyBatis Plus framework
  • MyBatis Plus provides a easier way to dynamically set condition and updated fields
  • base on Query Condition : combined MyBatis Plus and Kotlin, so called MyBatis++
  • MyBatis++ provides a more easier way to build complicated conditions
  • and supports update values through an Example bean

MyBatis++ Controller Abilities

this controller present multiple ways to do CURD with MyBatis++

you can choose your favorite ones or those match your current project most comfortably

package 
import 
import 
import 
import 
import 
import 
import 
import 
import 
import .*
@RestController
class UserController {
    @Autowired
    private lateinit var userMapper: UserMapper
    @GetMapping("/01")
    fun selectAll(): String {
        val userList = ()
        return ()
    }
    @GetMapping("/02")
    fun selectByName(): String {
        val user = ("Jimmy")
        return ().orEmpty()
    }
    @GetMapping("/03")
    fun selectByCondition(): String {
        val condition = condition { (User::name, "Jimmy") }
        val users = (())
        return ()
    }
    @GetMapping("/04")
    fun insert(): String {
        val user = User()
         = ()
        (user)
        return ()
    }
    @GetMapping("/05")
    fun insertOrUpdate(): String {
        val user = User()
         = "1"
         = ()
        (user)
        return ()
    }
    @GetMapping("/06")
    fun updateByCondition(): String {
        val cond1 = condition { (User::id) }
        val cond2 = condition { (User::name, "Jimmy") }
        val cond3 = condition { (User::age, 15) }
        val cond4 = condition {
            (User::name, "Jimmy")
            (User::age, 18)
        }
        val condition = cond1 and cond2 and cond3 attributes cond4
        val count = (())
        return ()
    }
    @GetMapping("/07")
    fun updateByEntityAndCondition(): String {
        val entity = User()
         = "Updated"
         = 36
        val cond1 = condition { (User::id) }
        val cond2 = condition { (User::name, "Jimmy") }
        val cond3 = condition { (User::age, 35) }
        val condition = cond1 and (cond2 or cond3)
        val count = (entity, ())
        return ()
    }
    @GetMapping("/08")
    fun updateByExampleAndCondition(): String {
        val example = UserExample()
         = 18
        val cond1 = condition { (User::id) }
        val cond2 = condition { (User::name, "Jimmy") }
        val cond3 = condition { (User::age, 35) }
        val condition = cond1 and (cond2 or cond3) values example
        val count = (())
        return ()
    }
    @GetMapping("/09")
    fun selectCrossTables(): String {
        val userRoles = ()
        return ()
    }
}

Configure Plugins and Repositories

pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement {
    repositoriesMode = RepositoriesMode.PREFER_SETTINGS
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
buildscript {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
plugins {
    id("") version "2.0.21" apply false
    id("") version "2.0.21" apply false
    id("") version "2.0.21" apply false
    id("") version "3.4.1" apply false
}
include("spring-mybatis")

Apply Plugins and Add Dependencies

plugins {
    id("")
    id("")
    id("")
    id("")
}
java {
    toolchain {
        languageVersion = (17)
    }
}
dependencies {
    val springBootVersion = "3.4.1"
    val springCloudVersion = "4.2.0"
    val springCloudAlibabaVersion = "2023.0.3.2"
    // commons
    api(".hellogoogle2000:kotlin-commons:1.0.19")
    // kotlin
    api(":kotlin-reflect:2.0.21")
    // spring
    api(":spring-boot-starter:$springBootVersion")
    api(":spring-boot-starter-web:$springBootVersion")
    api(":spring-cloud-starter-bootstrap:$springCloudVersion")
    // mybatis
    api(":quick-spring-boot-starter-mybatis-plus:2025.01.22")
}

MyBatis++ Spring Properties

# service
=10003
=mybatis
=dev
-properties=false
# mybatis
=root
=123456789
=jdbc:mysql://localhost:3306/dev?characterEncoding=utf-8&serverTimezone=UTC

MyBatis++ Application

package 
import 
import 
import 
@SpringBootApplication
@MapperScan(basePackages = [""])
class MybatisApplication
fun main(args: Array<String>) {
    runApplication<MybatisApplication>(*args)
}

MyBatis++ Beans

package 
import 
import 
class User {
    @TableId(type = IdType.ASSIGN_UUID)
    var id = ""
    var name = ""
    var age = 0
}
package 
class UserExample {
    var id: String? = null
    var name: String? = null
    var age: Int? = null
}
package 
class UserRoleQueryResult {
    var name = ""
    var role = ""
}

MyBatis++ Mapper

mapper sometimes called interface, service or repository in other projects

package 
import 
import 
import 
import 
interface UserMapper : BaseMapper<User> {
    @Select("select * from user")
    fun selectAll(): MutableList<User>
    @Select("select * from user where name = #{name}")
    fun selectUserByName(name: String): User?
    @Select(
        """
          select 
             as name,
             as role 
          from user left join role
          on  = 
        """
    )
    fun selectUserRole(): List<UserRoleQueryResult>
}

MyBatis++ Query Builder

this is the core component to build query condition and examples

difference between entity and example is :

entity will update all field, while example only update non-null fields

package 
import 
import 
import .KProperty1
import 
fun interface ConditionConfigurator<T : Any> {
    fun configure(wrapper: KtUpdateWrapper<T>)
}
data class QueryCondition<T : Any>(
    val configurator: ConditionConfigurator<T>
)
inline fun <reified T : Any> QueryCondition<T>.build(): KtUpdateWrapper<T> {
    val wrapper = KtUpdateWrapper(T::)
    (wrapper)
    return wrapper
}
inline fun <reified T : Any> condition(configurator: ConditionConfigurator<T>): QueryCondition<T> {
    return QueryCondition(configurator)
}
infix fun <T : Any> QueryCondition<T>.and(other: QueryCondition<T>): QueryCondition<T> {
    val configurator = ConditionConfigurator {
        (it)
         { (it) }
    }
    return QueryCondition(configurator)
}
infix fun <T : Any> QueryCondition<T>.or(other: QueryCondition<T>): QueryCondition<T> {
    val configurator = ConditionConfigurator {
        (it)
         { (it) }
    }
    return QueryCondition(configurator)
}
infix fun <T : Any> QueryCondition<T>.not(other: QueryCondition<T>): QueryCondition<T> {
    val configurator = ConditionConfigurator {
        (it)
         { (it) }
    }
    return QueryCondition(configurator)
}
infix fun <T : Any> QueryCondition<T>.attributes(other: QueryCondition<T>): QueryCondition<T> {
    val configurator = ConditionConfigurator {
        (it)
        (it)
    }
    return QueryCondition(configurator)
}
inline infix fun <reified T : Any, reified S : Any> QueryCondition<T>.values(example: S): QueryCondition<T> {
    val configurator = ConditionConfigurator { wrapper ->
        (wrapper)
        val properties = S::
         { propertyS ->
            val value = (example)
             { it != null } ?: return@forEach
            val property = T::()
             { it != null } ?: return@forEach
            (property, value)
        }
    }
    return QueryCondition(configurator)
}
inline fun <reified T : Any> KClass<T>.findPropertyByName(name: String): KProperty1<T, *>? {
    return  {  == name }
}

This is all about this article about Spring Boot Mybatis++ 2025. For more related Spring Boot Mybatis++ 2025, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!