天天看点

spring boot + kotlin + sharing-jdbc(dangdang)

build.gradle.kts

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
   id("org.springframework.boot") version "2.2.0.RELEASE"
   id("io.spring.dependency-management") version "1.0.8.RELEASE"
   kotlin("jvm") version "1.3.50"
   kotlin("plugin.spring") version "1.3.50"
   kotlin("plugin.jpa") version "1.3.50"
}

group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8

val developmentOnly by configurations.creating
configurations {
   runtimeClasspath {
      extendsFrom(developmentOnly)
   }
}

repositories {
   mavenCentral()
}

dependencies {
   implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
   implementation("org.jetbrains.kotlin:kotlin-reflect")
   implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
   implementation("org.springframework.boot:spring-boot-starter-web")
   developmentOnly("org.springframework.boot:spring-boot-devtools")
   testImplementation("org.springframework.boot:spring-boot-starter-test")
   implementation("com.alibaba:druid:1.1.20")
   implementation("com.dangdang:sharding-jdbc-core:1.5.4.1")
   implementation("mysql:mysql-connector-java:8.0.18")
   implementation("org.springframework.boot:spring-boot-starter-data-jpa:2.2.0.RELEASE")
}

tasks.withType<Test> {
   useJUnitPlatform()
}

tasks.withType<KotlinCompile> {
   kotlinOptions {
      freeCompilerArgs = listOf("-Xjsr305=strict")
      jvmTarget = "1.8"
   }
}
           

core class

package com.example.blog.config

import com.dangdang.ddframe.rdb.sharding.api.ShardingValue
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.SingleKeyDatabaseShardingAlgorithm
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm
import com.google.common.collect.Range
import org.springframework.stereotype.Component

@Component
class DatabaseShardingAlgorithm(val database0Config: Database0Config,
                                val database1Config: Database1Config) : SingleKeyDatabaseShardingAlgorithm<Long> {
    override fun doInSharding(availableTargetNames: MutableCollection<String>?, shardingValue: ShardingValue<Long>?): MutableCollection<String> {
        var result = mutableListOf<String>()
        for ( value in shardingValue!!.values){
            if(value <= 20L) result.add(database0Config.databaseName)
            else result.add(database1Config.databaseName)
        }
        return result
    }

    override fun doEqualSharding(availableTargetNames: MutableCollection<String>?, shardingValue: ShardingValue<Long>?): String {
        var value = shardingValue!!.value

        var result  = if(value <= 20L) database0Config.databaseName
        else database1Config.databaseName
        return result

    }

    override fun doBetweenSharding(availableTargetNames: MutableCollection<String>?, shardingValue: ShardingValue<Long>?): MutableCollection<String> {
        var result = mutableListOf<String>()
        var range : Range<Long> = shardingValue!!.valueRange
        var lower = range.lowerEndpoint()
        var upper = range.upperEndpoint()
        for(value in lower..upper){
            if(value <= 20L) result.add(database0Config.databaseName)
            else result.add(database1Config.databaseName)
        }
        return result
    }
}

@Component
class TableShardingAlgorithm(val database0Config: Database0Config,
                                val database1Config: Database1Config) : SingleKeyTableShardingAlgorithm<Long> {
    override fun doInSharding(availableTargetNames: MutableCollection<String>?, shardingValue: ShardingValue<Long>?): MutableCollection<String> {

        var result = mutableListOf<String>()
        for(value in shardingValue!!.values){
            for(tablename in availableTargetNames!!){
                if(tablename.endsWith("${value%2}")){
                    result.add(tablename)
                }
            }
        }

        return result
    }

    override fun doEqualSharding(tablenames: MutableCollection<String>?, shardingValue: ShardingValue<Long>?): String {

        tablenames!!.forEach {
            if(it.endsWith("${shardingValue!!.value % 2}")) {
                return it
            }
        }

        throw IllegalArgumentException()

    }

    override fun doBetweenSharding(availableTargetNames: MutableCollection<String>?, shardingValue: ShardingValue<Long>?): MutableCollection<String> {
        var result = mutableListOf<String>()
        var range: Range<Long> = shardingValue!!.valueRange

        var lower = range.lowerEndpoint()
        var upper = range.upperEndpoint()

        for(i in lower..upper){
            for(name in availableTargetNames!!){
                if(name.endsWith("${i%2}")){
                    result.add(name)
                }
            }
        }

        return result
    }

}
           
package com.example.blog.config

import com.alibaba.druid.pool.DruidDataSource
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.stereotype.Component
import javax.sql.DataSource

@ConfigurationProperties(prefix = "database0")
@Component
class Database0Config {

    var url: String = ""
    var username: String = ""
    var password: String = ""
    var driverClassName: String = ""
    var databaseName: String = ""

    fun createDataSource(): DataSource {
        var result = DruidDataSource()
        result.url = this.url
        result.username = this.username
        result.password = this.password
        result.driverClassName = this.driverClassName
        return result
    }

}

@ConfigurationProperties(prefix = "database1")
@Component
class Database1Config {

    var url: String = ""
    var username: String = ""
    var password: String = ""
    var driverClassName: String = ""
    var databaseName: String = ""

    fun createDataSource(): DataSource {
        var result = DruidDataSource()
        result.url = this.url
        result.username = this.username
        result.password = this.password
        result.driverClassName = this.driverClassName
        return result
    }
}
           
package com.example.blog.config

import com.dangdang.ddframe.rdb.sharding.api.ShardingDataSourceFactory
import com.dangdang.ddframe.rdb.sharding.api.rule.DataSourceRule
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule
import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.SingleKeyDatabaseShardingAlgorithm
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy
import com.dangdang.ddframe.rdb.sharding.keygen.DefaultKeyGenerator
import com.dangdang.ddframe.rdb.sharding.keygen.KeyGenerator
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import javax.sql.DataSource

@Configuration
open class DatasourceConfig(val database0Config: Database0Config,
                            val database1Config: Database1Config,
                            val databaseShardingAlgorithm: SingleKeyDatabaseShardingAlgorithm<Long>,
                            val tableShardingAlgorithm: SingleKeyTableShardingAlgorithm<Long>) {

    @Bean
    open fun getDataSource(): DataSource {
        var map = mutableMapOf(
                database0Config.databaseName to database0Config.createDataSource(),
                database1Config.databaseName to database1Config.createDataSource())

        var rule = DataSourceRule(map, database0Config.databaseName)

        var table0: TableRule = TableRule.builder("goods")
                .actualTables(listOf("goods_0", "goods_1"))
                .dataSourceRule(rule).build()
        var shardingRule = ShardingRule.builder()
                .dataSourceRule(rule)
                .tableRules(listOf(table0))
                .databaseShardingStrategy(DatabaseShardingStrategy("goods_id", databaseShardingAlgorithm))
                .tableShardingStrategy(TableShardingStrategy("goods_type", tableShardingAlgorithm))
                .build()

        return ShardingDataSourceFactory.createDataSource(shardingRule)
    }

    @Bean
    open fun keyGenerator(): KeyGenerator {
        return DefaultKeyGenerator()
    }
}
           
package com.example.blog.entity

import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Table


@Entity
@Table
class Goods {
    @Id
    var goodsId : Long = 0
    var goodsName: String = ""
    var goodsType: Long = 0
}
           
package com.example.blog.repository

import com.example.blog.entity.Goods
import org.springframework.data.jpa.repository.JpaRepository

interface GoodsRepository : JpaRepository<Goods,Long> {
    fun findAllByGoodsIdBetween(goodsId1 : Long,goodsId2: Long) : List<Goods>
    fun findAllByGoodsIdIn(goodsIds: List<Long>) : List<Goods>
}
           
package com.example.blog.rest

import com.example.blog.entity.Goods
import com.example.blog.repository.GoodsRepository
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class GoodsResouce(private val goodsRepository: GoodsRepository) {

    @GetMapping("/save")
    fun save() : String {
        for(i in 0..40) {
            var goods = Goods()
            goods.goodsId = i.toLong()
            goods.goodsName = "shangpin" + i
            goods.goodsType = i.toLong() + 1
            goodsRepository.save(goods)
        }
        return "Success"
    }

    @GetMapping("select")
    fun select(): String = goodsRepository.findAll().toString()

    @GetMapping("delete")
    fun delete() = goodsRepository.deleteAll()

    @GetMapping("query1")
    fun query1() : Any = goodsRepository.findAllByGoodsIdBetween(10,30)

    @GetMapping("query2")
    fun query2() : Any = goodsRepository.findAllByGoodsIdIn(listOf(10,15,20,25))

}
           
package com.example.blog

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.runApplication
import org.springframework.transaction.annotation.EnableTransactionManagement

@SpringBootApplication(exclude = [DataSourceAutoConfiguration::class])
@EnableTransactionManagement(proxyTargetClass = true)
@EnableConfigurationProperties
open class BlogApplication

fun main(args: Array<String>) {
   runApplication<BlogApplication>(*args)
}
           
##Jpa配置
spring.jpa.database: mysql
spring.jpa.show-sql: true
spring.jpa.hibernate.ddl-auto: none

  ##数据库配置
  ##数据库database0地址
database0.url: jdbc:mysql://localhost:3306/database0?characterEncoding=utf8&useSSL=false
  ##数据库database0用户名
database0.username: root
  ##数据库database0密码
database0.password: root
  ##数据库database0驱动
database0.driverClassName: com.mysql.cj.jdbc.Driver
  ##数据库database0名称
database0.databaseName: database0

  ##数据库database1地址
database1.url: jdbc:mysql://localhost:3306/database1?characterEncoding=utf8&useSSL=false
  ##数据库database1用户名
database1.username: root
  ##数据库database1密码
database1.password: root
  ##数据库database1驱动
database1.driverClassName: com.mysql.cj.jdbc.Driver
  ##数据库database1名称
database1.databaseName: database1
server.port: 8081