preface

Many people know about Mybatis, know about Jpa, but probably know very little about Spring-data-JDBC. Note that we are talking about data-JDBC here, not plain JDBC. It has some jPA-like features, such as the ability to derive SQL from method names, basic CRUD, and the ability to write native SQL. Crucially, it is very clean and does not rely on Hibernte or JPA.

A, use,start.spring.io/Create a demo

Spring Data JDBC with Java configuration


// @EnableJdbcRepositories create an implementation for the Repository interface
/ / AbstractJdbcConfiguration Spring JDBC Data needs many kinds of bean by default
@Configuration
@EnableJdbcRepositories(basePackages = "com.example.springdatajdbctest")
public class ApplicationConfiguration extends AbstractJdbcConfiguration {



    /** * To create a DataSource, use springBoot's default connection pool. You can also use the Druid * ConfigurationProperties annotation. To create DataSource */

    @Bean
    @ConfigurationProperties(prefix="spring.datasource" )
    public DataSource dataSource(a) {
        return DataSourceBuilder.create().build();
    }
    /** * The built-in database type is officially used@Beanpublic DataSource dataSource() { EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); return builder.setType(EmbeddedDatabaseType.H2).build(); } * /

    / * * * NamedParameterJdbcOperations is Spring Data * JDBC is used to access the database@param dataSource
     * @return* /
    @Bean
    NamedParameterJdbcOperations namedParameterJdbcOperations(DataSource dataSource) {
        return new NamedParameterJdbcTemplate(dataSource);
    }

    /** * provides transaction management *@param dataSource
     * @return* /
    @Bean
    TransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
Copy the code

The corresponding contents of application.properties are as follows:

Spring. The datasource. JDBC - url = JDBC: mysql: / / 127.0.0.1 / SSS? useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQuerie s=true&useAffectedRows=true spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver spring.datasource.username = root spring.datasource.password = ****Copy the code

Three, database build table, build entity class

create table user_info
(
    id          int auto_increment  primary key,
    name        varchar(32)       not null,
    age         int               not null,
    sex         tinyint default 1 not null,
    create_time datetime          not null,
    update_time datetime          not null
)
    comment 'User table';
Copy the code

@Data
public class UserInfo extends BaseEntity{
    ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
    @Id
    private Integer id ;
    private String name;
    private Integer age;
    private Integer sex;
}

@Data
public class BaseEntity {
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

Copy the code

4. Establish the storage interface UserInfoRepository

/** * The CrudRepository interface already provides some common interfaces, so it inherits CrudRepository */
public interface UserInfoRepository extends CrudRepository<UserInfo.Integer> {}Copy the code
/ * * * can also inherit PagingAndSortingRepository, it inherits the CrudRepository, sorting and paging default method * /
public interface UserInfoRepository extends PagingAndSortingRepository<UserInfo.Integer> {}Copy the code

Five, run:

@SpringBootTest
@RunWith(SpringRunner.class)
class SpringDataJdbcTestApplicationTests {

	@Autowired
	private UserInfoRepository userInfoRepository;

	@Test
	public void testGet(a) {
		Optional<UserInfo> userInfo = userInfoRepository.findById(1);
		System.out.println(userInfo.get());
	}

	@Test
	public void testCount(a) {
		long count = userInfoRepository.count();
		System.out.println(count);
	}
Copy the code

}

Keywords query methods

If the default method does not have the method we need, we can also write the keyword query method as a rule. SQL can be parsed by method names with keywords, for example

public interface UserInfoRepository extends PagingAndSortingRepository<UserInfo.Integer> {
    List<UserInfo> findByName(String ame);
}
Copy the code

This way, we can query the results we want without writing an SQL statement. The keyword findBy is used here, followed by both the required query criteria and, of course, composite query support. Such as

List<UserInfo> findByNameAndAge(String name,Integer age);
Copy the code

Of course, other keyword queries are also supported. See the table below Keyword mode, which is limited to attributes that can be used in clauses WHERE does not use joins

If you don’t like the keyword method, you can customize the method name, or you can use @query to define the Query method

	@Query("select name, age from user_info u where u.name = :name")
	List<UserInfo> getUserInfoByName(String name);
Copy the code

If you want to modify or remove it, just add a comment @modifying, like this:

@Modifying
@Query("update user_info set age=:age where name = :name")
Boolean updateAgeById(String name,Integer age);

@Modifying
@Query("delete from user_info where id = :id")
Boolean deleteRecord(Integer id);
Copy the code

Do you feel very convenient, no longer use to write SQL

Life cycle event mechanisms

Spring Data JDBC operations can be combined as events with ApplicationListener events for example, listening for all pre-insert operations. Here we will only demonstrate printing logs:

@Configuration
@Slf4j
public class CommonEventConfiguration {
    @Bean
    public ApplicationListener<BeforeSaveEvent<Object>> loggingSaves() {

        return event -> {
            Object entity = event.getEntity();
            log.info("{} is getting saved.", entity); }; }}Copy the code

Of course, you don’t want to listen for all the operations, you can specify a specific table operation, as follows:

@Slf4j
@Repository
public class UserSavedListener extends AbstractRelationalEventListener<UserInfo> {

    @Override
    protected void onAfterSave(AfterSaveEvent<UserInfo> userInfoAfterSaveEvent) {
        log.info("User :{}, saved successfully",userInfoAfterSaveEvent.getEntity()); }}Copy the code

Execute the test code:

@Test
public void testInsert(a) {
	UserInfo userInfo =new UserInfo();
	userInfo.setName("Fifty");
	userInfo.setAge(20);
	userInfo.setSex(1);
	UserInfo result = userInfoRepository.save(userInfo);
	System.out.println(result);
}
Copy the code

Execution Result:

Available events are:

8. Physical callback

The Spring Data infrastructure provides hooks to modify entities before and after invoking certain methods. As you may have noticed, we do not assign values to the creation time and update time of the user_info table. Both times in the database have values, and this is done using entity callbacks.

Create an entity callback class

@Component
public class DefaultingEntityCallback implements BeforeSaveCallback<BaseEntity> {

    @Override
    public BaseEntity onBeforeSave(BaseEntity baseEntity, MutableAggregateChange<BaseEntity> mutableAggregateChange) {
        baseEntity.setCreateTime(LocalDateTime.now());
        baseEntity.setUpdateTime(LocalDateTime.now());
        returnbaseEntity; }}Copy the code

In another scenario, AfterLoadCallback can be used to desensitize the user’s sensitive information after the query results come out

To be continued