spring-guides / gs-accessing-data-mysql

Accessing data with MySQL :: Learn how to set up and manage user accounts on MySQL and how to configure Spring Boot to connect to it at runtime.
http://spring.io/guides/gs/accessing-data-mysql/
Apache License 2.0
201 stars 314 forks source link

:spring_version: current :spring_boot_version: 3.2.0 :Controller: http://docs.spring.io/spring/docs/{spring_version}/javadoc-api/org/springframework/stereotype/Controller.html :SpringApplication: http://docs.spring.io/spring-boot/docs/{spring_boot_version}/api/org/springframework/boot/SpringApplication.html :toc: :icons: font :source-highlighter: prettify :project_id: gs-accessing-data-mysql :java_version: 17 :build_system: gradle :build_name: accessing-data-mysql :build_version: 0.0.1-SNAPSHOT :network_container: guide-mysql

This guide walks you through the process of creating a Spring application connected to a MySQL Database (as opposed to an in-memory, embedded database, which most of the other guides and many sample applications use). It uses Spring Data JPA to access the database, but this is only one of many possible choices (for example, you could use plain Spring JDBC).

== What You Will Build

You will create a MySQL database, build a Spring application, and connect it to the newly created database.

NOTE: MySQL is licensed with the GPL, so any program binary that you distribute with it must use the GPL, too. See the https://www.gnu.org/licenses/gpl.html[GNU General Public Licence].

// required variables: {java_version}, {project_id} include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/guide_introduction.adoc[]

== Setting up the MySQL Database

Before you can build your application, you first need to configure a MySQL database. //required variables: none include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/docker_compose_support.adoc[]

[[scratch]] == Starting with Spring Initializr

You can use this https://start.spring.io/#!type=maven-project&language=java&packaging=jar&groupId=com.example&artifactId=accessing-data-mysql&name=accessing-data-mysql&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.accessing-data-mysql&dependencies=web,data-jpa,mysql,docker-compose,testcontainers[pre-initialized project] and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.

To manually initialize the project:

. Navigate to https://start.spring.io. This service pulls in all the dependencies you need for an application and does most of the setup for you. . Choose either Gradle or Maven and the language you want to use. This guide assumes that you chose Java. . Click Dependencies and select Spring Web, Spring Data JPA, MySQL Driver, Docker Compose Support, and Testcontainers. . Click Generate. . Download the resulting ZIP file, which is an archive of a web application that is configured with your choices.

NOTE: If your IDE has the Spring Initializr integration, you can complete this process from your IDE.

== Create the @Entity Model

You need to create the entity model, as the following listing (in src/main/java/com/example/accessingdatamysql/User.java) shows:

==== [source,java,tabsize=2]

include::complete/src/main/java/com/example/accessingdatamysql/User.java[]

====

Hibernate automatically translates the entity into a table.

== Create the Repository

You need to create the repository that holds user records, as the following listing (in src/main/java/com/example/accessingdatamysql/UserRepository.java) shows:

==== [source,java,tabsize=2]

include::complete/src/main/java/com/example/accessingdatamysql/UserRepository.java[]

====

Spring automatically implements this repository interface in a bean that has the same name (with a change in the case -- it is called userRepository).

== Create a Controller

You need to create a controller to handle HTTP requests to your application, as the following listing (in src/main/java/com/example/accessingdatamysql/MainController.java) shows:

==== [source,java,tabsize=2]

include::complete/src/main/java/com/example/accessingdatamysql/MainController.java[]

====

NOTE: The preceding example explicitly specifies POST and GET for the two endpoints. By default, @RequestMapping maps all HTTP operations.

== Create an Application Class

Spring Initializr creates a simple class for the application. The following listing shows the class that Initializr created for this example (in src/main/java/com/example/accessingdatamysql/AccessingDataMysqlApplication.java):

==== [source,java,tabsize=2]

include::initial/src/main/java/com/example/accessingdatamysql/AccessingDataMysqlApplication.java[]

====

For this example, you need not modify the AccessingDataMysqlApplication class.

Spring Initializr adds the @SpringBootApplication annotation to our main class. @SpringBootApplication is a convenience annotation that adds all of the following:

== Run the Application

At this point, you can now run the application to see your code in action. You can run the main method through your IDE or from the command line. Note that, if you have cloned the project from the solution repository, your IDE may look in the wrong place for the compose.yaml file. You can configure your IDE to look in the correct place or you could use the command line to run the application. The ./gradlew bootRun and ./mvnw spring-boot:run commands launch the application and automatically find the compose.yaml file.

== Test the Application

Now that the application is running, you can test it by using curl or some similar tool. You have two HTTP endpoints that you can test:

GET localhost:8080/demo/all: Gets all data. POST localhost:8080/demo/add: Adds one user to the data.

The following curl command adds a user:

==== [source,sh]

$ curl http://localhost:8080/demo/add -d name=First -d email=someemail@someemailprovider.com

====

The reply should be as follows:

==== [source,sh]

Saved

====

The following command shows all the users:

==== [source,sh]

$ curl http://localhost:8080/demo/all

====

The reply should be as follows:

==== [source,json]

[{"id":1,"name":"First","email":"someemail@someemailprovider.com"}]

====

== Preparing to Build the Application

To package and run the application, we need to provide an external MySQL database rather than using Spring Boot Docker Compose Support. For this task, we can reuse the provided compose.yaml file with a few modifications: First, modify the ports entry in compose.yaml to be 3306:3306. Second, add a container_name of guide-mysql.

After these steps, the compose.yaml file should be:

[source,yaml]

services: mysql: container_name: 'guide-mysql' image: 'mysql:latest' environment:

Third, we need to tell our application how to connect to the database. This step was previously handled automatically with Spring Boot Docker Compose support. To do so, modify the application.properties file so that it is now:

[source,yaml]

spring.jpa.hibernate.ddl-auto=update spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase spring.datasource.username=myuser spring.datasource.password=secret spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.show-sql: true

// required: {build_system}, {build_name}, {build_version}, {network_container} // optional: omit_native_build include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/build_and_execute_guide.adoc[]

== Test the Application in Docker

If you ran the application using a Docker instruction above, a simple curl command from a terminal or command line will no longer work. This is because we are running our containers in a https://docs.docker.com/compose/networking/[Docker network] that is not accessible from the terminal or command line. To run curl commands, we can start a third container to run our curl commands and attach it to the same network.

First, obtain an interactive shell to a new container that is running on the same network as the MySQL database and the application: [source, bash]

docker run --rm --network container:guide-mysql -it alpine

Next, from the shell inside of the container, install curl: [source, bash]

apk add curl

Finally, you can run the curl commands as described in <<_test_the_application>>.

== Make Some Security Changes

When you are on a production environment, you may be exposed to SQL injection attacks. A hacker may inject DROP TABLE or any other destructive SQL commands. So, as a security practice, you should make some changes to your database before you expose the application to your users.

The following command revokes all the privileges from the user associated with the Spring application:

==== [source,sh]

mysql> revoke all on db_example.* from 'myuser'@'%';

====

Now the Spring application cannot do anything in the database.

The application must have some privileges, so use the following command to grant the minimum privileges the application needs:

==== [source,sh]

mysql> grant select, insert, delete, update on db_example.* to 'myuser'@'%';

====

Removing all privileges and granting some privileges gives your Spring application the privileges necessary to make changes to only the data of the database and not the structure (schema).

When you want to make changes to the database:

. Regrant permissions. . Change the spring.jpa.hibernate.ddl-auto to update. . Re-run your applications.

Then repeat the two commands shown here to make your application safe for production use again. Better still, use a dedicated migration tool, such as Flyway or Liquibase.

== Summary

Congratulations! You have just developed a Spring application that is bound to a MySQL database and is ready for production!

== See Also

The following guides may also be helpful:

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/footer.adoc[]