springboot學習筆記13-數據訪問-JDBC整合

一、整合JDBC數據源

1、JDBC:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <!--<scope>runtime</scope>-->
</dependency>

如果需要添加版本 也可以對驅動器添加版本。

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
</dependency>

使用yml文件進行配置:

application.yml:

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://47.97.192.241:3307/jdbcdata?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
    driver-class-name: com.mysql.jdbc.Driver

測試連接:

 @Test
    void contextLoads() throws SQLException {
        System.out.println("----------------");
        System.out.println(dataSource.getClass());
        Connection connection = dataSource.getConnection();
        System.out.println(connection.toString());
        connection.close();
    }

連接成功.

效果:

​ 默認使用的是class com.zaxxer.hikari.HikariDataSource作爲數據源

數據源相關配置都在com\zaxxer\hikari\HikariConfig.class包下

自動配置原理:

​ 自動配置都放在org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration這個包下。

數據源配置文件爲:org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration

獲取配置過程:

org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration配置文件下:

拿一個來舉例:

@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
	@ConditionalOnMissingBean(DataSource.class)
	@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource",
			matchIfMissing = true)
	static class Tomcat {
		@Bean
		@ConfigurationProperties(prefix = "spring.datasource.tomcat")
		org.apache.tomcat.jdbc.pool.DataSource dataSource(DataSourceProperties properties) {
			org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(properties,
					org.apache.tomcat.jdbc.pool.DataSource.class);
			DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(properties.determineUrl());
			String validationQuery = databaseDriver.getValidationQuery();
			if (validationQuery != null) {
				dataSource.setTestOnBorrow(true);
				dataSource.setValidationQuery(validationQuery);
			}
			return dataSource;
		}
	}
org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(properties,
					org.apache.tomcat.jdbc.pool.DataSource.class);

代碼意思爲,調用createDataSource這個函數,並傳入properties對象和tomcat的class類,properties從容器中取出來;

我們來看看createDataSource這個函數:

@SuppressWarnings("unchecked")
	protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {
		return (T) properties.initializeDataSourceBuilder().type(type).build();
	}

這個函數使用properties對象調用**initializeDataSourceBuilder.type(type).build()**初始化函數:

@SuppressWarnings("unchecked")
	public T build() {
		Class<? extends DataSource> type = getType();
		DataSource result = BeanUtils.instantiateClass(type);
		maybeGetDriverClassName();
		bind(result);
		return (T) result;
	}

build對其properties文件和DataSource對象進行綁定。

並且在DataSourceBuilder這個類中:

@SuppressWarnings("unchecked")
	public T build() {
		Class<? extends DataSource> type = getType();
		DataSource result = BeanUtils.instantiateClass(type);
		maybeGetDriverClassName();
		bind(result);
		return (T) result;
	}

	private void maybeGetDriverClassName() {
		if (!this.properties.containsKey("driverClassName") && this.properties.containsKey("url")) {
			String url = this.properties.get("url");
			String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
			this.properties.put("driverClassName", driverClass);
		}
	}

	private void bind(DataSource result) {
		ConfigurationPropertySource source = new MapConfigurationPropertySource(this.properties);
		ConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();
		aliases.addAliases("url", "jdbc-url");
		aliases.addAliases("username", "user");
		Binder binder = new Binder(source.withAliases(aliases));
		binder.bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(result));
	}

	@SuppressWarnings("unchecked")
	public <D extends DataSource> DataSourceBuilder<D> type(Class<D> type) {
		this.type = type;
		return (DataSourceBuilder<D>) this;
	}

	public DataSourceBuilder<T> url(String url) {
		this.properties.put("url", url);
		return this;
	}

	public DataSourceBuilder<T> driverClassName(String driverClassName) {
		this.properties.put("driverClassName", driverClassName);
		return this;
	}

	public DataSourceBuilder<T> username(String username) {
		this.properties.put("username", username);
		return this;
	}

	public DataSourceBuilder<T> password(String password) {
		this.properties.put("password", password);
		return this;
	}

	@SuppressWarnings("unchecked")
	public static Class<? extends DataSource> findType(ClassLoader classLoader) {
		for (String name : DATA_SOURCE_TYPE_NAMES) {
			try {
				return (Class<? extends DataSource>) ClassUtils.forName(name, classLoader);
			}
			catch (Exception ex) {
				// Swallow and continue
			}
		}
		return null;
	}

	private Class<? extends DataSource> getType() {
		Class<? extends DataSource> type = (this.type != null) ? this.type : findType(this.classLoader);
		if (type != null) {
			return type;
		}
		throw new IllegalStateException("No supported DataSource type found");
	}

這個類中,我們可以看到,在這個類中進行了username、password、typedriverNameClass的綁定配置。

經過以上配置,properties配置文件和DataSource就綁定好了,自動配置完畢。

然後我們可以在org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer中看到,sql文件的設置格式:

我們在頂部可以看見:

/**
 * Initialize a {@link DataSource} based on a matching {@link DataSourceProperties}
 * config.
 *
 * @author Dave Syer
 * @author Phillip Webb
 * @author Eddú Meléndez
 * @author Stephane Nicoll
 * @author Kazuki Shimizu
 */

然後點入DataSourceProperties文件,如果你是反編譯文件,那麼這裏就是文件格式,如果你是源碼文件,這裏就是我這種形式。

我們來看看這個文件:

這裏面設置有以下屬性:

private ClassLoader classLoader;
private String name;
private boolean generateUniqueName;
private Class<? extends DataSource> type;
private String driverClassName;
private String url;
private String username;
private String password;
private String jndiName;
private DataSourceInitializationMode initializationMode = DataSourceInitializationMode.EMBEDDED;

我們在這裏可以看見有一段註釋:

/**
	 * Platform to use in the DDL or DML scripts (such as schema-${platform}.sql or
	 * data-${platform}.sql).
	 */

這一段註釋的意思是我們自己設置的sql文件格式爲:schema-xx.sql和data-xx.sql,只有這兩種文件格式才能被得到自動加載和使用,其他類型的sql文件無法被加載和使用。

而且我們還可以發現:

/**
	 * Determine the username to use based on this configuration and the environment.
	 * @return the username to use
	 * @since 1.4.0
	 */
	public String determineUsername() {
		if (StringUtils.hasText(this.username)) {
			return this.username;
		}
		if (EmbeddedDatabaseConnection.isEmbedded(determineDriverClassName())) {
			return "sa";
		}
		return null;
	}

如果我們不指定username,那麼自動配置原理會返回一個sa的用戶名進行訪問。

/**
	 * Determine the password to use based on this configuration and the environment.
	 * @return the password to use
	 * @since 1.4.0
	 */
	public String determinePassword() {
		if (StringUtils.hasText(this.password)) {
			return this.password;
		}
		if (EmbeddedDatabaseConnection.isEmbedded(determineDriverClassName())) {
			return "";
		}
		return null;
	}

如果我們password不指定的話,會自動返回一個空的字符串作爲密碼。

private List<Resource> getScripts(String propertyName, List<String> resources, String fallback) {
		if (resources != null) {
			return getResources(propertyName, resources, true);
		}
		String platform = this.properties.getPlatform();
		List<String> fallbackResources = new ArrayList<>();
		fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");
		fallbackResources.add("classpath*:" + fallback + ".sql");
		return getResources(propertyName, fallbackResources, false);
	}

初始化函數:首先查看有沒有創表語句文件,如果有就添加到Resource的list列表對象中,然後從properties文件中得到username、password,然後執行runScripts函數。

void initSchema() {
		List<Resource> scripts = getScripts("spring.datasource.data", this.properties.getData(), "data");
		if (!scripts.isEmpty()) {
			if (!isEnabled()) {
				logger.debug("Initialization disabled (not running data scripts)");
				return;
			}
			String username = this.properties.getDataUsername();
			String password = this.properties.getDataPassword();
			runScripts(scripts, username, password);
		}
	}
private void runScripts(List<Resource> resources, String username, String password) {
		if (resources.isEmpty()) {
			return;
		}
		ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
		populator.setContinueOnError(this.properties.isContinueOnError());
		populator.setSeparator(this.properties.getSeparator());
		if (this.properties.getSqlScriptEncoding() != null) {
			populator.setSqlScriptEncoding(this.properties.getSqlScriptEncoding().name());
		}
		for (Resource resource : resources) {
			populator.addScript(resource);
		}
		DataSource dataSource = this.dataSource;
		if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
			dataSource = DataSourceBuilder.create(this.properties.getClassLoader())
					.driverClassName(this.properties.determineDriverClassName()).url(this.properties.determineUrl())
					.username(username).password(password).build();
		}
		DatabasePopulatorUtils.execute(populator, dataSource);
	}

創表函數:根據你給的sql文件,進行創表;fallback就是前面說的schema或者data,schema是創表語句,data是增刪改查語句。默認規則是schema-all.sql或者schema-xx.sql或者schema.sql;

private List<Resource> getScripts(String propertyName, List<String> resources, String fallback) {
		if (resources != null) {
			return getResources(propertyName, resources, true);
		}
		String platform = this.properties.getPlatform();
		List<String> fallbackResources = new ArrayList<>();
		fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");
		fallbackResources.add("classpath*:" + fallback + ".sql");
		return getResources(propertyName, fallbackResources, false);
	}

但是如果我們要自定義sql文件格式,我們可以在配置文件中設置,使用yml設置爲:

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://47.97.192.241:3307/jdbcdata?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
    driver-class-name: com.mysql.jdbc.Driver
    type: com.mysql.cj.jdbc.MysqlDataSource
    initialization-mode: always
    schema:
      - classpath:sys_config.sql

然後執行。記住對於springboot2.x以上的都需要添加initialization-mode: always設置,並且執行主函數,不是test函數。

注意:自定義的schema下方的classpath:後面不要有空格,不能有空格!!!!

使用JDBC進行實際查詢操作:

1、創建Controller:

package com.ogj.demojdbc.Controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.Map;

@Controller
public class HelloController {

    @Autowired
    JdbcTemplate jdbcTemplate;


    @GetMapping("/hello")
    @ResponseBody
    public Map<String, Object> hello(){
        List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from user");
        return list.get(0);
    }

}

2、前臺使用瀏覽器發出hello請求:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rSTbEQun-1584205341845)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200314152538094.png)]

其他添加、修改、刪除等操作都是同理可得。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章