In previous posts in this series, we have never explained how to manipulate a database, but in practice, almost all systems are dependent on data persistence, so it is very important to understand how to use an operational database.
There are many ways to manipulate a database in Spring. You can use JDBC, Hibernate, MyBatis, or any other data persistence framework. This blog will focus on how to manipulate a database in Spring through JDBC.
1. Project construction failure solved
Before we get into JDBC, let’s resolve a problem because a normally built application reported the following error when repacking:
We checked the Spring dependency in the pop.xml file:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> < version > 4.3.18. RELEASE < / version > < / dependency > < the dependency > < groupId > org. Springframework < / groupId > The < artifactId > spring - webmvc < / artifactId > < version > 4.3.18. RELEASE < / version > < / dependency > <! -- Spring aop support --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring aop</artifactId> < version > 5.1.8. RELEASE < / version > < / dependency > < the dependency > < groupId > org. Springframework < / groupId > < artifactId > spring - test < / artifactId > < version > 4.3.18. RELEASE < / version > < scope > test < / scope > < / dependency >Copy the code
Where, the version of spring-AOP is 5.1.8.RELEASE, and the version of the other three packages is 4.3.18.RELEASE, change the version of spring-aop to 4.3.18.RELEASE:
<! -- Spring aop support --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring aop</artifactId> < version > 4.3.18. RELEASE < / version > < / dependency >Copy the code
At this point, rebuild the package, no error, package success:
However, the above dependency can be reduced to the following:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.18. RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.18. RELEASE</version>
<scope>test</scope>
</dependency>
Copy the code
Since the spring-WebMVC package already includes spring-context and spring-AOP, there is no need to add these two dependencies repeatedly:
2. Configure the data source
MySql > create spring_action_db;
CREATE DATABASE spring_action_db DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
Copy the code
Create table book:
use spring_action_db; Create table Book (book_id bigint auto_increment COMMENT 'bookid ', book_name varchar(50) not null comment' bookid ', Author varchar(50) not null comment 'author ', create_by varchar(20) not null comment' creator ', Create_time datetime not NULL comment 'create time ', modify_by varchar(20) not null comment' create time ', Modify_time datetime not NULL comment 'Update ', column Book_pk primary key (book_id) comment' update ';Copy the code
When ready, create a data source for the configuration class configuration:
package chapter10.config;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("chapter10")
public class DataSourceConfig {
@Bean
public BasicDataSource dataSource(a) {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring_action_db");
dataSource.setUsername("root");
dataSource.setPassword("root");
returndataSource; }}Copy the code
Because we are using a MySql database, the Driver name is set to com.mysql.jdbc.driver.
If you are using a different type of database, change the name to the corresponding one.
Since we are using the MySql driver, we need to add the following dependencies to pom.xml, otherwise we will not get connections when accessing the database:
<! -- MySql driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
Copy the code
3. Use the original JDBC code
First, create a new database entity class Book:
package chapter10.domain;
import java.util.Date;
public class Book {
private Long bookId;
private String bookName;
private String author;
private String createBy;
private Date createTime;
private String modifyBy;
private Date modifyTime;
public Book(String bookName, String author, String createBy) {
this.bookName = bookName;
this.author = author;
this.createBy = createBy;
this.createTime = new Date();
this.modifyBy=createBy;
this.modifyTime=new Date();
}
public Book(Long bookId, String bookName, String author, String modifyBy) {
this.bookId = bookId;
this.bookName = bookName;
this.author = author;
this.modifyBy = modifyBy;
}
public Book(a) {}// omit the get and set methods
}
Copy the code
Then define the data access interface BookRepository and just add the addBook method for now:
package chapter10.db;
import chapter10.domain.Book;
public interface BookRepository {
void addBook(Book book);
}
Copy the code
3.1 Adding Data
Create a new data access implementation class JdbcBookRepository as follows:
package chapter10.db.jdbc;
import chapter10.db.BookRepository;
import chapter10.domain.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
@Repository
public class JdbcBookRepository implements BookRepository {
private static final String SQL_INSERT_BOOK =
"INSERT INTO book(book_name, author, create_by, create_time, modify_by, modify_time) VALUES (? ,? ,? ,? ,? ,?) ;";
@Autowired
private DataSource dataSource;
@Override
public void addBook(Book book) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
connection = dataSource.getConnection();
preparedStatement = connection.prepareStatement(SQL_INSERT_BOOK);
preparedStatement.setString(1, book.getBookName());
preparedStatement.setString(2, book.getAuthor());
preparedStatement.setString(3, book.getCreateBy());
preparedStatement.setTimestamp(4.new Timestamp(calendar.getTimeInMillis()));
preparedStatement.setString(5, book.getModifyBy());
preparedStatement.setTimestamp(6.new Timestamp(calendar.getTimeInMillis()));
preparedStatement.execute();
} catch (SQLException e) {
// Exception handling code
} finally {
try {
if(preparedStatement ! =null) {
preparedStatement.close();
}
if(connection ! =null) { connection.close(); }}catch (SQLException e) {
// Exception handling code}}}}Copy the code
Note: The @repository annotation is added to this class so that Spring can scan it to register it as a bean.
It is worth noting that we caught SQLException twice in this code because connection = datasource.getConnection (); , a preparedStatement. The execute (); , a preparedStatement. Close (); , the connection. The close (); Throws a checkable exception SQLException, so it must be caught in the method or the compiler will fail:
Connection getConnection(a) throws SQLException;
boolean execute(a) throws SQLException;
void close(a) throws SQLException;
void close(a) throws SQLException;
Copy the code
Finally, create a new unit test class, BookRepositoryTest, as follows:
package chapter10;
import chapter10.config.DataSourceConfig;
import chapter10.db.BookRepository;
import chapter10.domain.Book;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DataSourceConfig.class)
public class BookRepositoryTest {
@Autowired
private BookRepository bookRepository;
@Test
public void testAddBook(a) {
Book book = new Book("Spring In Action (4th edition)"."Craig Walls"."Stranger from Shencheng");
bookRepository.addBook(book);
book = new Book("Java EE Disruptors: Spring Boot in Action"."Wang Yunfei"."Stranger from Shencheng");
bookRepository.addBook(book);
book = new Book("RabbitMQ Field Guide"."Zhu Zhonghua"."Stranger from Shencheng"); bookRepository.addBook(book); }}Copy the code
Run testAddBook() and add data to the database successfully:
3.2 Updating Data
First, add the update method to the data access interface BookRepository:
void updateBook(Book book);
Copy the code
The method is then implemented in the data access implementation class JdbcBookRepository:
private static final String SQL_UPDATE_BOOK =
"UPDATE Book SET book_name = ? ,author = ? ,modify_by = ? ,modify_time=? WHERE book_id = ? ;";
@Override
public void updateBook(Book book) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
connection = dataSource.getConnection();
preparedStatement = connection.prepareStatement(SQL_UPDATE_BOOK);
preparedStatement.setString(1, book.getBookName());
preparedStatement.setString(2, book.getAuthor());
preparedStatement.setString(3, book.getModifyBy());
preparedStatement.setTimestamp(4.new Timestamp(calendar.getTimeInMillis()));
preparedStatement.setLong(5, book.getBookId());
preparedStatement.execute();
} catch (SQLException e) {
// Exception handling code
} finally {
try {
if(preparedStatement ! =null) {
preparedStatement.close();
}
if(connection ! =null) { connection.close(); }}catch (SQLException e) {
// Exception handling code}}}Copy the code
The code is almost the same as the previous new code, and I had to catch the check exception SQLException twice.
Finally, add the test method testUpdateBook to the test class BookRepositoryTest, as shown below:
@Test
public void testUpdateBook(a) {
Book book = new Book(1L."Spring In Action (4th edition)"."Craig Walls"."zwwhnly");
bookRepository.updateBook(book);
book = new Book(2L."Java EE Disruptors: Spring Boot in Action"."Wang Yunfei"."zwwhnly");
bookRepository.updateBook(book);
book = new Book(3L."RabbitMQ Field Guide"."Zhu Zhonghua"."zwwhnly");
bookRepository.updateBook(book);
}
Copy the code
After executing the test method, the data is updated successfully:
3.3 Searching for Data
First, add the update method to the data access interface BookRepository:
Book findBook(long bookId);
Copy the code
The method is then implemented in the data access implementation class JdbcBookRepository:
private static final String SQL_SELECT_BOOK =
"SELECT book_id,book_name,author,create_by,create_time,modify_by,modify_time FROM book WHERE book_id = ? ;";
@Override
public Book findBook(long bookId) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
Book book = null;
try {
connection = dataSource.getConnection();
preparedStatement = connection.prepareStatement(SQL_SELECT_BOOK);
preparedStatement.setLong(1, bookId);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
book = new Book();
book.setBookId(resultSet.getLong("book_id"));
book.setBookName(resultSet.getString("book_name"));
book.setAuthor(resultSet.getString("author"));
book.setCreateBy(resultSet.getString("create_by"));
book.setCreateTime(resultSet.getTimestamp("create_time"));
book.setModifyBy(resultSet.getString("modify_by"));
book.setModifyTime(resultSet.getTimestamp("modify_time")); }}catch (SQLException e) {
// Exception handling code
} finally {
try {
if(resultSet ! =null) {
resultSet.close();
}
if(preparedStatement ! =null) {
preparedStatement.close();
}
if(connection ! =null) { connection.close(); }}catch (SQLException e) {
// Exception handling code}}return book;
}
Copy the code
I found that the code was mostly the same as the previous new and updated code, and I also had to catch the check type exception SQLException twice.
Finally, add the test method testFindBook to the test class BookRepositoryTest, as shown below:
@Test
public void testFindBook(a) {
Book book = bookRepository.findBook(1L);
Assert.assertNotNull(book);
Assert.assertEquals(book.getBookName(), "Spring In Action (4th edition)");
}
Copy the code
When the test method is executed, the data query succeeds:
4. Use the JDBC template
Since most of the code is boilerplate code, and only a small portion of it is relevant to business logic, the good news is that Spring has already done this for us. Spring abstracts the data access boilerplate code into template classes. We can use template classes directly, simplifying JDBC code.
4.1 Adding Data
First, add the following configuration to the configuration class DataSourceConfig:
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
Copy the code
Then remove the @Repository annotation from the newly created JdbcBookRepository class.
Then, a new data access implementation class JdbcTemplateBookRepository as shown below:
package chapter10.db.jdbc;
import chapter10.db.BookRepository;
import chapter10.domain.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.stereotype.Repository;
import java.sql.Date;
@Repository
public class JdbcTemplateBookRepository implements BookRepository {
private static final String SQL_INSERT_BOOK =
"INSERT INTO book(book_name, author, create_by, create_time, modify_by, modify_time) VALUES (? ,? ,? ,? ,? ,?) ;";
@Autowired
private JdbcOperations jdbcOperations;
@Override
public void addBook(Book book) {
jdbcOperations.update(SQL_INSERT_BOOK, book.getBookName(),
book.getAuthor(),
book.getCreateBy(),
new Date(System.currentTimeMillis()),
book.getModifyBy(),
newDate(System.currentTimeMillis())); }}Copy the code
Note: The @repository annotation is added to this class so that Spring can scan it to register it as a bean.
Very simple there is no, from the previous code optimization to the current code, code cleanliness of the students estimate happy dead.
Because before the test class BookRepositoryTest, we injected is the interface, so we don’t need to modify the test class code, can direct access to the realization of the new JdbcTemplateBookRepository class methods:
@Autowired
private BookRepository bookRepository;
Copy the code
Run testAddBook() and the data is successfully added to the database:
4.2 Updating Data
In the data access implementation class JdbcTemplateBookRepository to add the following code:
private static final String SQL_UPDATE_BOOK =
"UPDATE Book SET book_name = ? ,author = ? ,modify_by = ? ,modify_time=? WHERE book_id = ? ;";
@Override
public void updateBook(Book book) {
jdbcOperations.update(SQL_UPDATE_BOOK, book.getBookName(),
book.getAuthor(),
book.getModifyBy(),
new Timestamp(System.currentTimeMillis()),
book.getBookId());
}
Copy the code
Then simply modify the previous test method testUpdateBook() :
@Test
public void testUpdateBook(a) {
Book book = new Book(4L."Spring In Action (4th edition)"."Craig Walls"."zwwhnly");
bookRepository.updateBook(book);
book = new Book(5L."Java EE Disruptors: Spring Boot in Action"."Wang Yunfei"."zwwhnly");
bookRepository.updateBook(book);
book = new Book(6L."RabbitMQ Field Guide"."Zhu Zhonghua"."zwwhnly");
bookRepository.updateBook(book);
}
Copy the code
Run the previous test method testUpdateBook() and the data is updated successfully:
4.3 Searching For Data
In the data access implementation class JdbcTemplateBookRepository to add the following code:
private static final String SQL_SELECT_BOOK =
"SELECT book_id,book_name,author,create_by,create_time,modify_by,modify_time FROM book WHERE book_id = ? ;";
@Override
public Book findBook(long bookId) {
return jdbcOperations.queryForObject(SQL_SELECT_BOOK, new BookRowMapper(), bookId);
}
private static final class BookRowMapper implements RowMapper<Book> {
@Override
public Book mapRow(ResultSet resultSet, int i) throws SQLException {
Book book = new Book();
book.setBookId(resultSet.getLong("book_id"));
book.setBookName(resultSet.getString("book_name"));
book.setAuthor(resultSet.getString("author"));
book.setCreateBy(resultSet.getString("create_by"));
book.setCreateTime(resultSet.getTimestamp("create_time"));
book.setModifyBy(resultSet.getString("modify_by"));
book.setModifyTime(resultSet.getTimestamp("modify_time"));
returnbook; }}Copy the code
TestFindBook ();
5. Source code and reference
Source code address: github.com/zwwhnly/spr… Welcome to download.
Craig Walls: Spring In Action (4th Edition)