1591068248
One of the more popular combinations of frontend and backend frameworks is Angular + Spring Boot. I’ve written several tutorials about how to combine the two—from keeping them as separate apps to combining them into a single artifact. But, what about deployment?
Developers ask me from time-to-time, “What’s the best way to do Angular deployment?” In this tutorial, I’ll show you several options. I’ll start by showing you how to deploy a Spring Boot app to Heroku. Then, I’ll show how to deploy a separate Angular app to Heroku.
There are lots of tutorials and information in the Java community on how to deploy Spring Boot apps, so I’ll leave the Spring Boot API on Heroku and show other Angular deployment options, including Firebase, Netlify, and AWS S3.
Since this tutorial is more about deployment than app creation, you can start with an existing Angular + Spring Boot app that I created previously. It’s a note-taking app that uses Kotlin and Spring Boot 2.2 on the backend and Angular 9 on the frontend. It’s secured with OpenID Connect (OIDC). If you’d like to see how I built it, you can read the following tutorials:
One of the slick features of this app is its full-featured data table that allows sorting, searching, and pagination. This feature is powered by NG Bootstrap and Spring Data JPA. Below is a screenshot:
Clone the application into an okta-angular-deployment-example
directory.
git clone https://github.com/oktadeveloper/okta-angular-bootstrap-example.git \
okta-angular-deployment-example
Prerequisites:
To begin, you’ll need to create a Heroku account. If you already have a Heroku account, log in to it. Once you’re logged in, create a new app. I named mine bootiful-angular
.
After creating your app, click on the Resources tab and add the Okta add-on.
If you haven’t entered a credit card for your Heroku account, you will receive an error. This is because Heroku requires you to have a credit card on file to use any of their add-ons, even for free ones. This is part of Heroku’s assurance to guard against misuse (real person, real credit card, etc.). I think this is a good security practice. Simply add a credit card to continue.
Click Provision and wait 20-30 seconds while your Okta account is created and OIDC apps are registered. Now go to your app’s Settings tab and click the Reveal Config Vars button. The Config Vars displayed are the environment variables you can use to configure both Angular and Spring Boot for OIDC authentication.
Create an okta.env
file in the okta-angular-deployment-example/notes-api
directory and copy the config vars into it, where $OKTA_*
is the value from Heroku.
export OKTA_OAUTH2_ISSUER=$OKTA_OAUTH2_ISSUER
export OKTA_OAUTH2_CLIENT_ID=$OKTA_OAUTH2_CLIENT_ID_WEB
export OKTA_OAUTH2_CLIENT_SECRET=$OKTA_OAUTH2_CLIENT_SECRET_WEB
If you’re on Windows without Windows Subsystem for Linux installed, create an okta.bat
file and use SET
instead of export
.
Start your Spring Boot app by navigating to the notes-api
directory, sourcing this file, and running ./gradlew bootRun
.
source okta.env
./gradlew bootRun
Environment Variables in IntelliJ IDEA
If you’re using IntelliJ IDEA, you can copy the contents of okta.env
and paste its values as environment variables. Edit the DemoApplication configuration and click on the Browse icon on the right-side of Environment variables.
Next, click the paste icon. You’ll need to delete export
in the Name column. Now you can run your Spring Boot app with Okta from IDEA!
Next, configure Angular for OIDC authentication by modifying its auth-routing.module.ts
to use the generated issuer, client ID, and update the callback URL.
notes/src/app/auth-routing.module.ts
const oktaConfig = {
issuer: '$OKTA_OAUTH2_ISSUER',
redirectUri: window.location.origin + '/callback',
clientId: '$OKTA_OAUTH2_CLIENT_ID_SPA',
pkce: true
};
const routes: Routes = [
...
{
path: '/callback',
component: OktaCallbackComponent
}
];
Install your Angular app’s dependencies and start it.
npm i
ng serve
Open http://localhost:4200
in your browser.
Click the Login button in the top right corner. You should be logged in straight-away, since you’re already logged in to Okta. If you want to see the full authentication flow, log out, or try it in a private window. You can use the $OKTA_ADMIN_EMAIL
and $OKTA_ADMIN_PASSWORD
from your Heroku config variables for credentials. Create a note to make sure everything works.
Commit your progress to Git from the top-level okta-angular-deployment-example
directory.
git commit -am "Add Okta OIDC Configuration"
There are a couple of things you should do to make your app ready for production.
You’re going to want to continue to develop locally—so you’ll want a production mode as well as a development mode.
I’m the type of developer that likes to use the latest releases of open source libraries. I do this to take advantage of new features, performance optimizations, and security fixes.
There’s a Gradle Use Latest Versions Plugin that provides a task to update dependencies to the latest version. Configure it by adding the following to the plugins
block at the top of notes-api/build.gradle.kts
.
plugins {
id("se.patrikerdes.use-latest-versions") version "0.2.13"
id("com.github.ben-manes.versions") version "0.28.0"
...
}
For compatibility with Spring Boot 2.3, you’ll need to update the Gradle Wrapper to use Gradle 6.3+.
./gradlew wrapper --gradle-version=6.5 --distribution-type=bin
Then run the following command in the notes-api
directory to update your dependencies to the latest released versions.
./gradlew useLatestVersions
You can verify everything still works by running ./gradlew bootRun
and navigating to http://localhost:8080/api/notes
. You should be redirected to Okta to log in, then back to your app.
If your app fails to start, you need to run source okta.env
first.
For the Angular client, you can use npm-check-updates to upgrade npm dependencies.
npm i -g npm-check-updates
ncu -u
At the time of this writing, this will upgrade Angular to version 9.1.9 and TypeScript to version 3.9.3. Angular 9 supports TypeScript versions >=3.6.4 and <3.9.0, so you’ll need to change package.json
to specify TypeScript 3.8.3.
"typescript": "~3.8.3"
Then run the following commands in the notes
directory:
npm i
npm audit fix
ng serve
Confirm you can still log in at http://localhost:4200
.
Commit all your changes to source control.
git commit -am "Update dependencies to latest versions"
There are a few places where localhost
is hard-coded:
notes-api/src/main/kotlin/…/DemoApplication.kt
has http://localhost:4200
notes/src/app/shared/okta/auth-interceptor.ts
has http://localhost
notes/src/app/note/note.service.ts
has http://localhost:8080
You need to change Spring Boot’s code so other origins can make CORS requests too. Angular’s code needs updating so access tokens will be sent to production URLs while API requests are sent to the correct endpoint.
Open the root directory in your favorite IDE and configure it so it loads notes-api
as a Gradle project. Open DemoApplication.kt
and change the simpleCorsFilter
bean so it configures the allowed origins from your Spring environment.
notes-api/src/main/kotlin/com/okta/developer/notes/DemoApplication.kt
import org.springframework.beans.factory.annotation.Value
@SpringBootApplication
class DemoApplication {
@Value("#{ @environment['allowed.origins'] ?: {} }")
private lateinit var allowedOrigins: List<String>
@Bean
fun simpleCorsFilter(): FilterRegistrationBean<CorsFilter> {
val source = UrlBasedCorsConfigurationSource()
val config = CorsConfiguration()
config.allowCredentials = true
config.allowedOrigins = allowedOrigins
config.allowedMethods = listOf("*");
config.allowedHeaders = listOf("*")
source.registerCorsConfiguration("/**", config)
val bean = FilterRegistrationBean(CorsFilter(source))
bean.order = Ordered.HIGHEST_PRECEDENCE
return bean
}
}
Define the allowed.origins
property in notes-api/src/main/resources/application.properties
.
allowed.origins=http://localhost:4200
Angular has an environment concept built-in. When you run ng build --prod
to create a production build, it replaces environment.ts
with environment.prod.ts
.
Open environment.ts
and add an apiUrl
variable for development.
notes/src/environments/environment.ts
export const environment = {
production: false,
apiUrl: 'http://localhost:8080'
};
Edit environment.prod.ts
to point to your production Heroku URL. Be sure to replace bootiful-angular
with your app’s name.
notes/src/environments/environment.prod.ts
export const environment = {
production: false,
apiUrl: 'https://bootiful-angular.herokuapp.com'
};
Update auth-interceptor.ts
to use environment.apiUrl
.
notes/src/app/shared/okta/auth.interceptor.ts
import { environment } from '../../../environments/environment';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
...
private async handleAccess(request: HttpRequest<any>, next: HttpHandler): Promise<HttpEvent<any>> {
const allowedOrigins = [environment.apiUrl];
...
}
}
Update notes.service.ts
as well.
notes/src/app/note/note.service.ts
import { environment } from '../../environments/environment';
...
export class NoteService {
...
api = `${environment.apiUrl}/api/notes`;
...
find(filter: NoteFilter): Observable<Note[]> {
...
const userNotes = `${environment.apiUrl}/user/notes`;
...
}
}
H2 is a SQL database that works nicely for development. In production, you’re going to want something a little more robust. Personally, I like PostgreSQL so I’ll use it in this example.
Similar to Angular’s environments, Spring and Maven have profiles that allow you to enable different behavior for different environments.
Open notes-api/build.gradle.kts
and change the H2 dependency so PostgreSQL is used when -Pprod
is passed in.
if (project.hasProperty("prod")) {
runtimeOnly("org.postgresql:postgresql")
} else {
runtimeOnly("com.h2database:h2")
}
At the bottom of the file, add the following code to make the prod
profile the default when -Pprod
is included in Gradle commands.
val profile = if (project.hasProperty("prod")) "prod" else "dev"
tasks.bootRun {
args("--spring.profiles.active=${profile}")
}
tasks.processResources {
rename("application-${profile}.properties", "application.properties")
}
Rename notes-api/src/main/resources/application.properties
to application-dev.properties
and add a URL for H2 so it will persist to disk, which retains data through restarts.
allowed.origins=http://localhost:4200
spring.datasource.url=jdbc:h2:file:./build/h2db/notes;DB_CLOSE_DELAY=-1
Create a notes-api/src/main/docker/postgresql.yml
so you can test your prod
profile settings.
version: '2'
services:
notes-postgresql:
image: postgres:12.1
environment:
- POSTGRES_USER=notes
- POSTGRES_PASSWORD=
ports:
- 5432:5432
Create an application-prod.properties
file in the same directory as application-dev.properties
. You’ll override these properties with environment variables when you deploy to Heroku.
notes-api/src/main/resources/application-prod.properties
allowed.origins=http://localhost:4200
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:postgresql://localhost:5432/notes
spring.datasource.username=notes
spring.datasource.password=
The word user
is a keyword in PostgreSQL, so you’ll need to change user
to username
in the Note
entity.
notes-api/src/main/kotlin/com/okta/developer/notes/DemoApplication.kt
data class Note(@Id @GeneratedValue var id: Long? = null,
var title: String? = null,
var text: String? = null,
@JsonIgnore var username: String? = null)
This will cause compilation errors and you’ll need to rename method names and variables to fix them.
Click to see the diff
You won’t want to pre-populate your production database with a bunch of notes, so add a @Profile
annotation to the top of DataInitializer
so it only runs for the dev
profile.
import org.springframework.context.annotation.Profile
...
@Profile("dev")
class DataInitializer(val repository: NotesRepository) : ApplicationRunner {...}
To test your profiles, start PostgreSQL using Docker Compose.
docker-compose -f src/main/docker/postgresql.yml up
If you have PostreSQL installed and running locally, you’ll need to stop the process for Docker Compose to work.
In another terminal, run your Spring Boot app.
source okta.env
./gradlew bootRun -Pprod
If it starts OK, confirm your Angular app can talk to it and get ready to deploy to production!
git commit -am "Configure environments for production"
One of the easiest ways to interact with Heroku is with the Heroku CLI. Install it before proceeding with the instructions below.
brew tap heroku/brew && brew install heroku
Open a terminal and log in to your Heroku account.
heroku login
Heroku expects you to have one Git repo per application. However, in this particular example, there are multiple apps in the same repo. This is called a “monorepo”, where many projects are stored in the same repository.
Luckily, there’s a heroku-buildpack-monorepo that allows you to deploy multiple apps from the same repo.
You should already have a Heroku app that you added Okta to. Let’s use it for hosting Spring Boot. Run heroku apps
and you’ll see the one you created.
$ heroku apps
=== matt.raible@okta.com Apps
bootiful-angular
You can run heroku config -a $APP_NAME
to see your Okta variables. In my case, I’ll be using bootiful-angular
for $APP_NAME
.
Associate your existing Git repo with the app on Heroku.
heroku git:remote -a $APP_NAME
Set the APP_BASE
config variable to point to the notes-api
directory. While you’re there, add the monorepo and Gradle buildpacks.
heroku config:set APP_BASE=notes-api
heroku buildpacks:add https://github.com/lstoll/heroku-buildpack-monorepo
heroku buildpacks:add heroku/gradle
Attach a PostgreSQL database to your app.
heroku addons:create heroku-postgresql
As part of this process, Heroku will create a DATASOURCE_URL
configuration variable. It will also automatically detect Spring Boot and set variables for SPRING_DATASOURCE_URL
, SPRING_DATASOURCE_USERNAME
, AND SPRING_DATASOURCE_PASSWORD
. These values will override what you have in application-prod.properties
.
By default, Heroku’s Gradle support runs ./gradlew build -x test
. Since you want it to run ./gradlew bootJar -Pprod
, you’ll need to override it by setting a GRADLE_TASK
config var.
heroku config:set GRADLE_TASK="bootJar -Pprod"
The $OKTA_*
environment variables don’t have the same names as the Okta Spring Boot starter expects. This is because the Okta Heroku Add-On creates two apps: SPA and web. The web app’s config variables end in _WEB
. You’ll have to make some changes so those variables are used for the Okta Spring Boot starter. One way to do so is to create a Procfile
in the notes-api
directory.
web: java -Dserver.port=$PORT -Dokta.oauth2.client-id=${OKTA_OAUTH2_CLIENT_ID_WEB} -Dokta.oauth2.client-secret=${OKTA_OAUTH2_CLIENT_SECRET_WEB} -jar build/lib/*.jar
I think it’s easier to rename the variable, so that’s what I recommend. Run the following command and remove _WEB
from the two variables that have it.
heroku config:edit
Now you’re ready to deploy! Take a deep breath and witness how Heroku can deploy your Spring Boot + Kotlin app with a simple git push
.
git push heroku master
When I ran this command, I received this output:
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Monorepo app detected
remote: Copied notes-api to root of app successfully
remote: -----> Gradle app detected
remote: -----> Spring Boot detected
remote: -----> Installing JDK 1.8... done
remote: -----> Building Gradle app...
remote: -----> executing ./gradlew bootJar -Pprod
remote: Downloading https://services.gradle.org/distributions/gradle-6.0.1-bin.zip
remote: ..........................................................................................
remote: > Task :compileKotlin
remote: > Task :compileJava NO-SOURCE
remote: > Task :processResources
remote: > Task :classes
remote: > Task :bootJar
remote:
remote: BUILD SUCCESSFUL in 1m 28s
remote: 3 actionable tasks: 3 executed
remote: -----> Discovering process types
remote: Procfile declares types -> (none)
remote: Default types for buildpack -> web
remote:
remote: -----> Compressing...
remote: Done: 91.4M
remote: -----> Launching...
remote: Released v1
remote: https://bootiful-angular.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/bootiful-angular.git
a1b10c4..6e298cf master -> master
Execution time: 2 min. 7 s.
Run heroku open
to open your app. You’ll be redirected to Okta to authenticate, then back to your app. It will display a 404 error message because you have nothing mapped to /
. You can fix that by adding a HomeController
with the following code.
package com.okta.developer.notes
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.security.oauth2.core.oidc.user.OidcUser
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class HomeController {
@GetMapping("/")
fun hello(@AuthenticationPrincipal user: OidcUser): String {
return "Hello, ${user.fullName}"
}
}
Commit this change and deploy it to Heroku.
git commit -am "Add HomeController"
git push heroku master
Now when you access the app, it should say hello.
An Angular app is composed of JavaScript, CSS, and HTML when built for production. It’s extremely portable because it’s just a set of static files. If you run ng build --prod
, the production-ready files will be created in dist/<app-name>
. In this section, you’ll learn how you can use your package.json
scripts to hook into Heroku’s lifecycle and how to deploy them with a simple git push
.
You’ll need to create another app on Heroku for the Angular frontend.
heroku create
Set the APP_BASE
config variable and add the necessary buildpacks to the app that was just created.
APP_NAME=<app-name-from-heroku-create>
heroku config:set APP_BASE=notes -a $APP_NAME
heroku buildpacks:add https://github.com/lstoll/heroku-buildpack-monorepo -a $APP_NAME
heroku buildpacks:add heroku/nodejs -a $APP_NAME
Change notes/package.json
to have a different start
script.
"start": "http-server-spa dist/notes index.html $PORT",
Add a heroku-postbuild
script to your package.json
:
"heroku-postbuild": "ng build --prod && npm install -g http-server-spa"
Commit your changes, add a new Git remote for this app, and deploy!
git commit -am "Prepare for Heroku"
git remote add angular https://git.heroku.com/$APP_NAME.git
git push angular master
When it finishes deploying, you can open your Angular app with:
heroku open --remote angular
If you experience any issues, you can run heroku logs --remote angular
to see your app’s log files.
You won’t be able to log in to your app until you modify its Login redirect URI on Okta. Log in to your Okta dashboard (tip: you can do this from the first Heroku app you created, under the Resources tab). Go to Applications > SPA > General > Edit. Add https://<angular-app-on-heroku>.herokuapp.com/callback
to the Login redirect URIs and https://<angular-app-on-heroku>.herokuapp.com
to the Logout redirect URIs.
You should be able to log in now, but you won’t be able to add any notes. This is because you need to update the allowed origins in your Spring Boot app. Run the following command to add an ALLOWED_ORIGINS
variable in your Spring Boot app.
heroku config:set ALLOWED_ORIGINS=https://$APP_NAME.herokuapp.com --remote heroku
Now you should be able to add a note. Pat yourself on the back for a job well done!
One issue you’ll experience is that you’re going to lose your data between restarts. This is because Hibernate is configured to update your database schema each time. Change it to simply validate your schema by overriding the ddl-auto
value in application-prod.properties
.
heroku config:set SPRING_JPA_HIBERNATE_DDL_AUTO=validate --remote heroku
#angular #spring-boot #java #web-development
1654075127
Amazon Aurora is a relational database management system (RDBMS) developed by AWS(Amazon Web Services). Aurora gives you the performance and availability of commercial-grade databases with full MySQL and PostgreSQL compatibility. In terms of high performance, Aurora MySQL and Aurora PostgreSQL have shown an increase in throughput of up to 5X over stock MySQL and 3X over stock PostgreSQL respectively on similar hardware. In terms of scalability, Aurora achieves enhancements and innovations in storage and computing, horizontal and vertical functions.
Aurora supports up to 128TB of storage capacity and supports dynamic scaling of storage layer in units of 10GB. In terms of computing, Aurora supports scalable configurations for multiple read replicas. Each region can have an additional 15 Aurora replicas. In addition, Aurora provides multi-primary architecture to support four read/write nodes. Its Serverless architecture allows vertical scaling and reduces typical latency to under a second, while the Global Database enables a single database cluster to span multiple AWS Regions in low latency.
Aurora already provides great scalability with the growth of user data volume. Can it handle more data and support more concurrent access? You may consider using sharding to support the configuration of multiple underlying Aurora clusters. To this end, a series of blogs, including this one, provides you with a reference in choosing between Proxy and JDBC for sharding.
AWS Aurora offers a single relational database. Primary-secondary, multi-primary, and global database, and other forms of hosting architecture can satisfy various architectural scenarios above. However, Aurora doesn’t provide direct support for sharding scenarios, and sharding has a variety of forms, such as vertical and horizontal forms. If we want to further increase data capacity, some problems have to be solved, such as cross-node database Join
, associated query, distributed transactions, SQL sorting, page turning, function calculation, database global primary key, capacity planning, and secondary capacity expansion after sharding.
It is generally accepted that when the capacity of a MySQL table is less than 10 million, the time spent on queries is optimal because at this time the height of its BTREE
index is between 3 and 5. Data sharding can reduce the amount of data in a single table and distribute the read and write loads to different data nodes at the same time. Data sharding can be divided into vertical sharding and horizontal sharding.
1. Advantages of vertical sharding
2. Disadvantages of vertical sharding
Join
can only be implemented by interface aggregation, which will increase the complexity of development.3. Advantages of horizontal sharding
4. Disadvantages of horizontal sharding
Join
is poor.Based on the analysis above, and the available studis on popular sharding middleware, we selected ShardingSphere, an open source product, combined with Amazon Aurora to introduce how the combination of these two products meets various forms of sharding and how to solve the problems brought by sharding.
ShardingSphere is an open source ecosystem including a set of distributed database middleware solutions, including 3 independent products, Sharding-JDBC, Sharding-Proxy & Sharding-Sidecar.
The characteristics of Sharding-JDBC are:
Hybrid Structure Integrating Sharding-JDBC and Applications
Sharding-JDBC’s core concepts
Data node: The smallest unit of a data slice, consisting of a data source name and a data table, such as ds_0.product_order_0.
Actual table: The physical table that really exists in the horizontal sharding database, such as product order tables: product_order_0, product_order_1, and product_order_2.
Logic table: The logical name of the horizontal sharding databases (tables) with the same schema. For instance, the logic table of the order product_order_0, product_order_1, and product_order_2 is product_order.
Binding table: It refers to the primary table and the joiner table with the same sharding rules. For example, product_order table and product_order_item are sharded by order_id, so they are binding tables with each other. Cartesian product correlation will not appear in the multi-tables correlating query, so the query efficiency will increase greatly.
Broadcast table: It refers to tables that exist in all sharding database sources. The schema and data must consist in each database. It can be applied to the small data volume that needs to correlate with big data tables to query, dictionary table and configuration table for example.
Download the example project code locally. In order to ensure the stability of the test code, we choose shardingsphere-example-4.0.0
version.
git clone
https://github.com/apache/shardingsphere-example.git
Project description:
shardingsphere-example
├── example-core
│ ├── config-utility
│ ├── example-api
│ ├── example-raw-jdbc
│ ├── example-spring-jpa #spring+jpa integration-based entity,repository
│ └── example-spring-mybatis
├── sharding-jdbc-example
│ ├── sharding-example
│ │ ├── sharding-raw-jdbc-example
│ │ ├── sharding-spring-boot-jpa-example #integration-based sharding-jdbc functions
│ │ ├── sharding-spring-boot-mybatis-example
│ │ ├── sharding-spring-namespace-jpa-example
│ │ └── sharding-spring-namespace-mybatis-example
│ ├── orchestration-example
│ │ ├── orchestration-raw-jdbc-example
│ │ ├── orchestration-spring-boot-example #integration-based sharding-jdbc governance function
│ │ └── orchestration-spring-namespace-example
│ ├── transaction-example
│ │ ├── transaction-2pc-xa-example #sharding-jdbc sample of two-phase commit for a distributed transaction
│ │ └──transaction-base-seata-example #sharding-jdbc distributed transaction seata sample
│ ├── other-feature-example
│ │ ├── hint-example
│ │ └── encrypt-example
├── sharding-proxy-example
│ └── sharding-proxy-boot-mybatis-example
└── src/resources
└── manual_schema.sql
Configuration file description:
application-master-slave.properties #read/write splitting profile
application-sharding-databases-tables.properties #sharding profile
application-sharding-databases.properties #library split profile only
application-sharding-master-slave.properties #sharding and read/write splitting profile
application-sharding-tables.properties #table split profile
application.properties #spring boot profile
Code logic description:
The following is the entry class of the Spring Boot application below. Execute it to run the project.
The execution logic of demo is as follows:
As business grows, the write and read requests can be split to different database nodes to effectively promote the processing capability of the entire database cluster. Aurora uses a reader/writer endpoint
to meet users' requirements to write and read with strong consistency, and a read-only endpoint
to meet the requirements to read without strong consistency. Aurora's read and write latency is within single-digit milliseconds, much lower than MySQL's binlog
-based logical replication, so there's a lot of loads that can be directed to a read-only endpoint
.
Through the one primary and multiple secondary configuration, query requests can be evenly distributed to multiple data replicas, which further improves the processing capability of the system. Read/write splitting can improve the throughput and availability of system, but it can also lead to data inconsistency. Aurora provides a primary/secondary architecture in a fully managed form, but applications on the upper-layer still need to manage multiple data sources when interacting with Aurora, routing SQL requests to different nodes based on the read/write type of SQL statements and certain routing policies.
ShardingSphere-JDBC provides read/write splitting features and it is integrated with application programs so that the complex configuration between application programs and database clusters can be separated from application programs. Developers can manage the Shard
through configuration files and combine it with ORM frameworks such as Spring JPA and Mybatis to completely separate the duplicated logic from the code, which greatly improves the ability to maintain code and reduces the coupling between code and database.
Create a set of Aurora MySQL read/write splitting clusters. The model is db.r5.2xlarge. Each set of clusters has one write node and two read nodes.
application.properties spring boot
Master profile description:
You need to replace the green ones with your own environment configuration.
# Jpa automatically creates and drops data tables based on entities
spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.show_sql=true
#spring.profiles.active=sharding-databases
#spring.profiles.active=sharding-tables
#spring.profiles.active=sharding-databases-tables
#Activate master-slave configuration item so that sharding-jdbc can use master-slave profile
spring.profiles.active=master-slave
#spring.profiles.active=sharding-master-slave
application-master-slave.properties sharding-jdbc
profile description:
spring.shardingsphere.datasource.names=ds_master,ds_slave_0,ds_slave_1
# data souce-master
spring.shardingsphere.datasource.ds_master.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_master.password=Your master DB password
spring.shardingsphere.datasource.ds_master.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_master.jdbc-url=Your primary DB data sourceurl spring.shardingsphere.datasource.ds_master.username=Your primary DB username
# data source-slave
spring.shardingsphere.datasource.ds_slave_0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_slave_0.password= Your slave DB password
spring.shardingsphere.datasource.ds_slave_0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_slave_0.jdbc-url=Your slave DB data source url
spring.shardingsphere.datasource.ds_slave_0.username= Your slave DB username
# data source-slave
spring.shardingsphere.datasource.ds_slave_1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_slave_1.password= Your slave DB password
spring.shardingsphere.datasource.ds_slave_1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_slave_1.jdbc-url= Your slave DB data source url
spring.shardingsphere.datasource.ds_slave_1.username= Your slave DB username
# Routing Policy Configuration
spring.shardingsphere.masterslave.load-balance-algorithm-type=round_robin
spring.shardingsphere.masterslave.name=ds_ms
spring.shardingsphere.masterslave.master-data-source-name=ds_master
spring.shardingsphere.masterslave.slave-data-source-names=ds_slave_0,ds_slave_1
# sharding-jdbc configures the information storage mode
spring.shardingsphere.mode.type=Memory
# start shardingsphere log,and you can see the conversion from logical SQL to actual SQL from the print
spring.shardingsphere.props.sql.show=true
As shown in the ShardingSphere-SQL log
figure below, the write SQL is executed on the ds_master
data source.
As shown in the ShardingSphere-SQL log
figure below, the read SQL is executed on the ds_slave
data source in the form of polling.
[INFO ] 2022-04-02 19:43:39,376 --main-- [ShardingSphere-SQL] Rule Type: master-slave
[INFO ] 2022-04-02 19:43:39,376 --main-- [ShardingSphere-SQL] SQL: select orderentit0_.order_id as order_id1_1_, orderentit0_.address_id as address_2_1_,
orderentit0_.status as status3_1_, orderentit0_.user_id as user_id4_1_ from t_order orderentit0_ ::: DataSources: ds_slave_0
---------------------------- Print OrderItem Data -------------------
Hibernate: select orderiteme1_.order_item_id as order_it1_2_, orderiteme1_.order_id as order_id2_2_, orderiteme1_.status as status3_2_, orderiteme1_.user_id
as user_id4_2_ from t_order orderentit0_ cross join t_order_item orderiteme1_ where orderentit0_.order_id=orderiteme1_.order_id
[INFO ] 2022-04-02 19:43:40,898 --main-- [ShardingSphere-SQL] Rule Type: master-slave
[INFO ] 2022-04-02 19:43:40,898 --main-- [ShardingSphere-SQL] SQL: select orderiteme1_.order_item_id as order_it1_2_, orderiteme1_.order_id as order_id2_2_, orderiteme1_.status as status3_2_,
orderiteme1_.user_id as user_id4_2_ from t_order orderentit0_ cross join t_order_item orderiteme1_ where orderentit0_.order_id=orderiteme1_.order_id ::: DataSources: ds_slave_1
Note: As shown in the figure below, if there are both reads and writes in a transaction, Sharding-JDBC routes both read and write operations to the master library. If the read/write requests are not in the same transaction, the corresponding read requests are distributed to different read nodes according to the routing policy.
@Override
@Transactional // When a transaction is started, both read and write in the transaction go through the master library. When closed, read goes through the slave library and write goes through the master library
public void processSuccess() throws SQLException {
System.out.println("-------------- Process Success Begin ---------------");
List<Long> orderIds = insertData();
printData();
deleteData(orderIds);
printData();
System.out.println("-------------- Process Success Finish --------------");
}
The Aurora database environment adopts the configuration described in Section 2.2.1.
3.2.4.1 Verification process description
Spring-Boot
project2. Perform a failover on Aurora’s console
3. Execute the Rest API
request
4. Repeatedly execute POST
(http://localhost:8088/save-user) until the call to the API failed to write to Aurora and eventually recovered successfully.
5. The following figure shows the process of executing code failover. It takes about 37 seconds from the time when the latest SQL write is successfully performed to the time when the next SQL write is successfully performed. That is, the application can be automatically recovered from Aurora failover, and the recovery time is about 37 seconds.
application.properties spring boot
master profile description
# Jpa automatically creates and drops data tables based on entities
spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.show_sql=true
#spring.profiles.active=sharding-databases
#Activate sharding-tables configuration items
#spring.profiles.active=sharding-tables
#spring.profiles.active=sharding-databases-tables
# spring.profiles.active=master-slave
#spring.profiles.active=sharding-master-slave
application-sharding-tables.properties sharding-jdbc
profile description
## configure primary-key policy
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123
spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds.t_order_item_$->{0..1}
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item_$->{order_id % 2}
spring.shardingsphere.sharding.tables.t_order_item.key-generator.column=order_item_id
spring.shardingsphere.sharding.tables.t_order_item.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order_item.key-generator.props.worker.id=123
# configure the binding relation of t_order and t_order_item
spring.shardingsphere.sharding.binding-tables[0]=t_order,t_order_item
# configure broadcast tables
spring.shardingsphere.sharding.broadcast-tables=t_address
# sharding-jdbc mode
spring.shardingsphere.mode.type=Memory
# start shardingsphere log
spring.shardingsphere.props.sql.show=true
1. DDL operation
JPA automatically creates tables for testing. When Sharding-JDBC routing rules are configured, the client
executes DDL, and Sharding-JDBC automatically creates corresponding tables according to the table splitting rules. If t_address
is a broadcast table, create a t_address
because there is only one master instance. Two physical tables t_order_0
and t_order_1
will be created when creating t_order
.
2. Write operation
As shown in the figure below, Logic SQL
inserts a record into t_order
. When Sharding-JDBC is executed, data will be distributed to t_order_0
and t_order_1
according to the table splitting rules.
When t_order
and t_order_item
are bound, the records associated with order_item
and order
are placed on the same physical table.
3. Read operation
As shown in the figure below, perform the join
query operations to order
and order_item
under the binding table, and the physical shard is precisely located based on the binding relationship.
The join
query operations on order
and order_item
under the unbound table will traverse all shards.
Create two instances on Aurora: ds_0
and ds_1
When the sharding-spring-boot-jpa-example
project is started, tables t_order
, t_order_item
,t_address
will be created on two Aurora instances.
application.properties springboot
master profile description
# Jpa automatically creates and drops data tables based on entities
spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.show_sql=true
# Activate sharding-databases configuration items
spring.profiles.active=sharding-databases
#spring.profiles.active=sharding-tables
#spring.profiles.active=sharding-databases-tables
#spring.profiles.active=master-slave
#spring.profiles.active=sharding-master-slave
application-sharding-databases.properties sharding-jdbc
profile description
spring.shardingsphere.datasource.names=ds_0,ds_1
# ds_0
spring.shardingsphere.datasource.ds_0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_0.jdbc-url= spring.shardingsphere.datasource.ds_0.username=
spring.shardingsphere.datasource.ds_0.password=
# ds_1
spring.shardingsphere.datasource.ds_1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_1.jdbc-url=
spring.shardingsphere.datasource.ds_1.username=
spring.shardingsphere.datasource.ds_1.password=
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds_$->{user_id % 2}
spring.shardingsphere.sharding.binding-tables=t_order,t_order_item
spring.shardingsphere.sharding.broadcast-tables=t_address
spring.shardingsphere.sharding.default-data-source-name=ds_0
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds_$->{0..1}.t_order
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123
spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds_$->{0..1}.t_order_item
spring.shardingsphere.sharding.tables.t_order_item.key-generator.column=order_item_id
spring.shardingsphere.sharding.tables.t_order_item.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order_item.key-generator.props.worker.id=123
# sharding-jdbc mode
spring.shardingsphere.mode.type=Memory
# start shardingsphere log
spring.shardingsphere.props.sql.show=true
1. DDL operation
JPA automatically creates tables for testing. When Sharding-JDBC’s library splitting and routing rules are configured, the client
executes DDL, and Sharding-JDBC will automatically create corresponding tables according to table splitting rules. If t_address
is a broadcast table, physical tables will be created on ds_0
and ds_1
. The three tables, t_address
, t_order
and t_order_item
will be created on ds_0
and ds_1
respectively.
2. Write operation
For the broadcast table t_address
, each record written will also be written to the t_address
tables of ds_0
and ds_1
.
The tables t_order
and t_order_item
of the slave library are written on the table in the corresponding instance according to the slave library field and routing policy.
3. Read operation
Query order
is routed to the corresponding Aurora instance according to the routing rules of the slave library .
Query Address
. Since address
is a broadcast table, an instance of address
will be randomly selected and queried from the nodes used.
As shown in the figure below, perform the join
query operations to order
and order_item
under the binding table, and the physical shard is precisely located based on the binding relationship.
As shown in the figure below, create two instances on Aurora: ds_0
and ds_1
When the sharding-spring-boot-jpa-example
project is started, physical tables t_order_01
, t_order_02
, t_order_item_01
,and t_order_item_02
and global table t_address
will be created on two Aurora instances.
application.properties springboot
master profile description
# Jpa automatically creates and drops data tables based on entities
spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.show_sql=true
# Activate sharding-databases-tables configuration items
#spring.profiles.active=sharding-databases
#spring.profiles.active=sharding-tables
spring.profiles.active=sharding-databases-tables
#spring.profiles.active=master-slave
#spring.profiles.active=sharding-master-slave
application-sharding-databases.properties sharding-jdbc
profile description
spring.shardingsphere.datasource.names=ds_0,ds_1
# ds_0
spring.shardingsphere.datasource.ds_0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_0.jdbc-url= 306/dev?useSSL=false&characterEncoding=utf-8
spring.shardingsphere.datasource.ds_0.username=
spring.shardingsphere.datasource.ds_0.password=
spring.shardingsphere.datasource.ds_0.max-active=16
# ds_1
spring.shardingsphere.datasource.ds_1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_1.jdbc-url=
spring.shardingsphere.datasource.ds_1.username=
spring.shardingsphere.datasource.ds_1.password=
spring.shardingsphere.datasource.ds_1.max-active=16
# default library splitting policy
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds_$->{user_id % 2}
spring.shardingsphere.sharding.binding-tables=t_order,t_order_item
spring.shardingsphere.sharding.broadcast-tables=t_address
# Tables that do not meet the library splitting policy are placed on ds_0
spring.shardingsphere.sharding.default-data-source-name=ds_0
# t_order table splitting policy
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds_$->{0..1}.t_order_$->{0..1}
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2}
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123
# t_order_item table splitting policy
spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds_$->{0..1}.t_order_item_$->{0..1}
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item_$->{order_id % 2}
spring.shardingsphere.sharding.tables.t_order_item.key-generator.column=order_item_id
spring.shardingsphere.sharding.tables.t_order_item.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order_item.key-generator.props.worker.id=123
# sharding-jdbc mdoe
spring.shardingsphere.mode.type=Memory
# start shardingsphere log
spring.shardingsphere.props.sql.show=true
1. DDL operation
JPA automatically creates tables for testing. When Sharding-JDBC’s sharding and routing rules are configured, the client
executes DDL, and Sharding-JDBC will automatically create corresponding tables according to table splitting rules. If t_address
is a broadcast table, t_address
will be created on both ds_0
and ds_1
. The three tables, t_address
, t_order
and t_order_item
will be created on ds_0
and ds_1
respectively.
2. Write operation
For the broadcast table t_address
, each record written will also be written to the t_address
tables of ds_0
and ds_1
.
The tables t_order
and t_order_item
of the sub-library are written to the table on the corresponding instance according to the slave library field and routing policy.
3. Read operation
The read operation is similar to the library split function verification described in section2.4.3.
The following figure shows the physical table of the created database instance.
application.properties spring boot
master profile description
# Jpa automatically creates and drops data tables based on entities
spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.show_sql=true
# activate sharding-databases-tables configuration items
#spring.profiles.active=sharding-databases
#spring.profiles.active=sharding-tables
#spring.profiles.active=sharding-databases-tables
#spring.profiles.active=master-slave
spring.profiles.active=sharding-master-slave
application-sharding-master-slave.properties sharding-jdbc
profile description
The url, name and password of the database need to be changed to your own database parameters.
spring.shardingsphere.datasource.names=ds_master_0,ds_master_1,ds_master_0_slave_0,ds_master_0_slave_1,ds_master_1_slave_0,ds_master_1_slave_1
spring.shardingsphere.datasource.ds_master_0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_master_0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_master_0.jdbc-url= spring.shardingsphere.datasource.ds_master_0.username=
spring.shardingsphere.datasource.ds_master_0.password=
spring.shardingsphere.datasource.ds_master_0.max-active=16
spring.shardingsphere.datasource.ds_master_0_slave_0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_master_0_slave_0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_master_0_slave_0.jdbc-url= spring.shardingsphere.datasource.ds_master_0_slave_0.username=
spring.shardingsphere.datasource.ds_master_0_slave_0.password=
spring.shardingsphere.datasource.ds_master_0_slave_0.max-active=16
spring.shardingsphere.datasource.ds_master_0_slave_1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_master_0_slave_1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_master_0_slave_1.jdbc-url= spring.shardingsphere.datasource.ds_master_0_slave_1.username=
spring.shardingsphere.datasource.ds_master_0_slave_1.password=
spring.shardingsphere.datasource.ds_master_0_slave_1.max-active=16
spring.shardingsphere.datasource.ds_master_1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_master_1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_master_1.jdbc-url=
spring.shardingsphere.datasource.ds_master_1.username=
spring.shardingsphere.datasource.ds_master_1.password=
spring.shardingsphere.datasource.ds_master_1.max-active=16
spring.shardingsphere.datasource.ds_master_1_slave_0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_master_1_slave_0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_master_1_slave_0.jdbc-url=
spring.shardingsphere.datasource.ds_master_1_slave_0.username=
spring.shardingsphere.datasource.ds_master_1_slave_0.password=
spring.shardingsphere.datasource.ds_master_1_slave_0.max-active=16
spring.shardingsphere.datasource.ds_master_1_slave_1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds_master_1_slave_1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds_master_1_slave_1.jdbc-url= spring.shardingsphere.datasource.ds_master_1_slave_1.username=admin
spring.shardingsphere.datasource.ds_master_1_slave_1.password=
spring.shardingsphere.datasource.ds_master_1_slave_1.max-active=16
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds_$->{user_id % 2}
spring.shardingsphere.sharding.binding-tables=t_order,t_order_item
spring.shardingsphere.sharding.broadcast-tables=t_address
spring.shardingsphere.sharding.default-data-source-name=ds_master_0
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds_$->{0..1}.t_order_$->{0..1}
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2}
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123
spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds_$->{0..1}.t_order_item_$->{0..1}
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item_$->{order_id % 2}
spring.shardingsphere.sharding.tables.t_order_item.key-generator.column=order_item_id
spring.shardingsphere.sharding.tables.t_order_item.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.t_order_item.key-generator.props.worker.id=123
# master/slave data source and slave data source configuration
spring.shardingsphere.sharding.master-slave-rules.ds_0.master-data-source-name=ds_master_0
spring.shardingsphere.sharding.master-slave-rules.ds_0.slave-data-source-names=ds_master_0_slave_0, ds_master_0_slave_1
spring.shardingsphere.sharding.master-slave-rules.ds_1.master-data-source-name=ds_master_1
spring.shardingsphere.sharding.master-slave-rules.ds_1.slave-data-source-names=ds_master_1_slave_0, ds_master_1_slave_1
# sharding-jdbc mode
spring.shardingsphere.mode.type=Memory
# start shardingsphere log
spring.shardingsphere.props.sql.show=true
1. DDL operation
JPA automatically creates tables for testing. When Sharding-JDBC’s library splitting and routing rules are configured, the client
executes DDL, and Sharding-JDBC will automatically create corresponding tables according to table splitting rules. If t_address
is a broadcast table, t_address
will be created on both ds_0
and ds_1
. The three tables, t_address
, t_order
and t_order_item
will be created on ds_0
and ds_1
respectively.
2. Write operation
For the broadcast table t_address
, each record written will also be written to the t_address
tables of ds_0
and ds_1
.
The tables t_order
and t_order_item
of the slave library are written to the table on the corresponding instance according to the slave library field and routing policy.
3. Read operation
The join
query operations on order
and order_item
under the binding table are shown below.
3. Conclusion
As an open source product focusing on database enhancement, ShardingSphere is pretty good in terms of its community activitiy, product maturity and documentation richness.
Among its products, ShardingSphere-JDBC is a sharding solution based on the client-side, which supports all sharding scenarios. And there’s no need to introduce an intermediate layer like Proxy, so the complexity of operation and maintenance is reduced. Its latency is theoretically lower than Proxy due to the lack of intermediate layer. In addition, ShardingSphere-JDBC can support a variety of relational databases based on SQL standards such as MySQL/PostgreSQL/Oracle/SQL Server, etc.
However, due to the integration of Sharding-JDBC with the application program, it only supports Java language for now, and is strongly dependent on the application programs. Nevertheless, Sharding-JDBC separates all sharding configuration from the application program, which brings relatively small changes when switching to other middleware.
In conclusion, Sharding-JDBC is a good choice if you use a Java-based system and have to to interconnect with different relational databases — and don’t want to bother with introducing an intermediate layer.
Author
Sun Jinhua
A senior solution architect at AWS, Sun is responsible for the design and consult on cloud architecture. for providing customers with cloud-related design and consulting services. Before joining AWS, he ran his own business, specializing in building e-commerce platforms and designing the overall architecture for e-commerce platforms of automotive companies. He worked in a global leading communication equipment company as a senior engineer, responsible for the development and architecture design of multiple subsystems of LTE equipment system. He has rich experience in architecture design with high concurrency and high availability system, microservice architecture design, database, middleware, IOT etc.
1622798007
In this tutorial, I will show you how to build a full stack Angular 12 + Spring Boot JWT Authentication example. The back-end server uses Spring Boot with Spring Security for JWT Authentication & Role based Authorization, Spring Data JPA for interacting with database. The front-end will be built using Angular 12 with HttpInterceptor & Form validation.
Related Posts:
– Angular 12 + Spring Boot: CRUD example
– Angular 12 + Spring Boot: File upload example
– Spring Boot, MongoDB: JWT Authentication with Spring Security
Contents [hide]
#angular #full stack #spring #angular #angular 12 #authentication #authorization #jwt #login #registration #security #spring boot #spring security #token based authentication
1642110180
Spring is a blog engine written by GitHub Issues, or is a simple, static web site generator. No more server and database, you can setup it in free hosting with GitHub Pages as a repository, then post the blogs in the repository Issues.
You can add some labels in your repository Issues as the blog category, and create Issues for writing blog content through Markdown.
Spring has responsive templates, looking good on mobile, tablet, and desktop.Gracefully degrading in older browsers. Compatible with Internet Explorer 10+ and all modern browsers.
Get up and running in seconds.
For the impatient, here's how to get a Spring blog site up and running.
Repository Name
.index.html
file to edit the config variables with yours below.$.extend(spring.config, {
// my blog title
title: 'Spring',
// my blog description
desc: "A blog engine written by github issues [Fork me on GitHub](https://github.com/zhaoda/spring)",
// my github username
owner: 'zhaoda',
// creator's username
creator: 'zhaoda',
// the repository name on github for writting issues
repo: 'spring',
// custom page
pages: [
]
})
CNAME
file if you have.Issues
feature.https://github.com/your-username/your-repo-name/issues?state=open
.New Issue
button to just write some content as a new one blog.http://your-username.github.io/your-repo-name
, you will see your Spring blog, have a test.http://localhost/spring/dev.html
.dev.html
is used to develop, index.html
is used to runtime.spring/
├── css/
| ├── boot.less #import other less files
| ├── github.less #github highlight style
| ├── home.less #home page style
| ├── issuelist.less #issue list widget style
| ├── issues.less #issues page style
| ├── labels.less #labels page style
| ├── main.less #commo style
| ├── markdown.less #markdown format style
| ├── menu.less #menu panel style
| ├── normalize.less #normalize style
| ├── pull2refresh.less #pull2refresh widget style
| └── side.html #side panel style
├── dist/
| ├── main.min.css #css for runtime
| └── main.min.js #js for runtime
├── img/ #some icon, startup images
├── js/
| ├── lib/ #some js librarys need to use
| ├── boot.js #boot
| ├── home.js #home page
| ├── issuelist.js #issue list widget
| ├── issues.js #issues page
| ├── labels.js #labels page
| ├── menu.js #menu panel
| ├── pull2refresh.less #pull2refresh widget
| └── side.html #side panel
├── css/
| ├── boot.less #import other less files
| ├── github.less #github highlight style
| ├── home.less #home page style
| ├── issuelist.less #issue list widget style
| ├── issues.less #issues page style
| ├── labels.less #labels page style
| ├── main.less #commo style
| ├── markdown.less #markdown format style
| ├── menu.less #menu panel style
| ├── normalize.less #normalize style
| ├── pull2refresh.less #pull2refresh widget style
| └── side.html #side panel style
├── dev.html #used to develop
├── favicon.ico #website icon
├── Gruntfile.js #Grunt task config
├── index.html #used to runtime
└── package.json #nodejs install config
http://localhost/spring/dev.html
, enter the development mode.css
, js
etc.dev.html
view change.bash
$ npm install
* Run grunt task.
```bash
$ grunt
http://localhost/spring/index.html
, enter the runtime mode.master
branch into gh-pages
branch if you have.If you are using, please tell me.
Download Details:
Author: zhaoda
Source Code: https://github.com/zhaoda/spring
License: MIT License
1622597127
In this tutorial, we will learn how to build a full stack Spring Boot + Angular 12 example with a CRUD App. The back-end server uses Spring Boot with Spring Web MVC for REST Controller and Spring Data JPA for interacting with embedded database (H2 database). Front-end side is made with Angular 12, HttpClient, Router and Bootstrap 4.
Run both Project on same server/port:
How to Integrate Angular with Spring Boot Rest API
Contents [hide]
#angular #full stack #spring #angular #angular 12 #crud #h2 database #mysql #postgresql #rest api #spring boot #spring data jpa
1622600862
In this tutorial, we will learn how to build a full stack Angular 12 + Spring Boot + PostgreSQL example with a CRUD App. The back-end server uses Spring Boot with Spring Web MVC for REST Controller and Spring Data JPA for interacting with PostgreSQL database. Front-end side is made with Angular 12, HTTPClient, Router and Bootstrap 4.
Older versions:
– Angular 10 + Spring Boot + PostgreSQL example: CRUD App
– Angular 11 + Spring Boot + PostgreSQL example: CRUD App
Contents [hide]
#angular #full stack #spring #angular #angular 12 #crud #postgresql #rest api #spring boot #spring data jpa