什么是JDBC模板(jdbcTemplate)
模板就是事先準(zhǔn)備好的東西,你只需要去套用就可以,JDBCTemplate就是這樣的模板,通過設(shè)置JDBCTemplate可以減少對數(shù)據(jù)庫的繁瑣操作,例如連接數(shù)據(jù)庫,獲得鏈接關(guān)閉,獲得statement,resultset,preparedstatement這些等等。
傳統(tǒng)的JDBC應(yīng)用步驟:
- 1.指定數(shù)據(jù)庫連接參數(shù)
- 2.打開數(shù)據(jù)庫連接
- 3.聲明SQL語句
- 4.預(yù)編譯并執(zhí)行SQL語句
- 5.遍歷查詢結(jié)果(如果需要的話)
- 6.處理每一次遍歷操作
- 7.處理拋出的任何異常
- 8.處理事務(wù)
- 9.關(guān)閉數(shù)據(jù)庫連接
JDBC的缺點就是太麻煩了,不易編碼,容易出錯,不利于開發(fā)者把精力投入到業(yè)務(wù)上去。簡化JDBC就是新技術(shù)的目標(biāo)。Spring對數(shù)據(jù)庫的操作在jdbc上面做了深層次的封裝,使用spring的注入功能,可以把DataSource注冊到JdbcTemplate之中。
使用Spring的JdbcTemplate ( 不帶 SpringBoot ),選擇注冊DataSourceInitializer Bean來初始化數(shù)據(jù)庫
@Configuration
@ComponentScan
@EnableTransactionManagement
@PropertySource(value = { "classpath:application.properties" })
public class AppConfig
{
@Autowired
private Environment env;
@Value("${init-db:false}")
private String initDatabase;
@Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer()
{
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource)
{
return new JdbcTemplate(dataSource);
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource)
{
return new DataSourceTransactionManager(dataSource);
}
@Bean
public DataSource dataSource()
{
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
@Bean
public DataSourceInitializer dataSourceInitializer(DataSource dataSource)
{
DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
dataSourceInitializer.setDataSource(dataSource);
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
databasePopulator.addScript(new ClassPathResource("data.sql"));
dataSourceInitializer.setDatabasePopulator(databasePopulator);
dataSourceInitializer.setEnabled(Boolean.parseBoolean(initDatabase));
return dataSourceInitializer;
}
}
使用此配置后,我們可以將JdbcTemplate注入到Data Access組件中以與數(shù)據(jù)庫進行交互。
public class User
{
private Integer id;
private String name;
private String email;
// setters & getters
}
@Repository
public class UserRepository
{
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional(readOnly=true)
public List<User> findAll() {
return jdbcTemplate.query("select * from users", new UserRowMapper());
}
}
class UserRowMapper implements RowMapper<User>
{
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException
{
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setEmail(rs.getString("email"));
return user;
}
}
SpringBoot配置JdbcTemplate
使用SpringBoot,我們可以利用自動配置功能,而無需自己配置bean。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
通過添加spring-boot-starter-jdbc模塊,我們得到以下自動配置:
spring-boot-starter-jdbc模塊可傳遞地拉出用于配置DataSource bean的tomcat-jdbc- {version} .jar。
如果您沒有明確定義任何DataSource bean,并且在類路徑中有任何嵌入式數(shù)據(jù)庫驅(qū)動程序(例如H2,HSQL或Derby),那么SpringBoot將使用內(nèi)存中的數(shù)據(jù)庫設(shè)置自動注冊DataSource bean。
-
如果您還沒有注冊任何以下類型的bean,那么SpringBoot將自動注冊它們。
- PlatformTransactionManager(DataSourceTransactionManager)
我們可以有schema.sql文件和根類路徑data.sql文件,這SpringBoot會自動使用初始化database.In除了schema.sql文件和data.sql,春天開機就會加載的架構(gòu)-
{platform} .sql文件(如果在根類路徑中可用)。 這里的平臺值是屬性spring.datasource.platform的值,可以是hsqldb,h2,oracle,mysql,postgresql等 。您可以使用以下屬性來自定義腳本的默認(rèn)名稱:
spring.datasource.schema =創(chuàng)建db.sql
出于任何原因,如果您想自己控制和配置DataSource bean,則可以在Configuration類中配置DataSource bean。
@Configuration
public class DataSourceConfig {
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource.center")
DataSource dsCenter() {
return DataSourceBuilder.create().build();
}
@Bean(name = "hisDatasource")
@ConfigurationProperties(prefix = "spring.datasource.his")
DataSource dsHis() {
return DataSourceBuilder.create().build();
}
}
application.property
spring.datasource.center.dirverClassName: com.mysql.jdbc.Driver
spring.datasource.center.jdbc-url:jdbc:mysql://gz-cdb-6oo2gh6t.sql.tencentcdb.com:62179/kfzx_hospital?tinyInt1isBit=false&useUnicode=true&useSSL=false&characterEncoding=UTF-8
spring.datasource.center.username:root
spring.datasource.center.password:!QAZ2wsx#EDC4rfv
spring.datasource.his.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.his.jdbc-url=jdbc:oracle:thin:@10.0.0.6:1521/BSHIS
spring.datasource.his.username:zy_zj
spring.datasource.his.password:zy_zj
JdbcTemplate
queryForInt()/queryForLong()
使用queryForInt()主要是為了獲取數(shù)據(jù)庫中記錄總數(shù),獲取指定條件的記錄數(shù)等,不需要對應(yīng)列名,只需要返回一個數(shù)據(jù)即可.queryForLong()是同理的.
queryForMap()
如果你想查詢到結(jié)果并命名的話,你可以使用queryForMap(),查詢到的值更改列名為別名,然后使用map.get("別名")來獲取.
可能遇到的錯:

queryForObject()
其實本質(zhì)上queryForObject()和queryForInt()是一直的,只不過可以返回一個非int的值,比如你查詢指定id的對象的某一個屬性,可以使用Object進行接收,而不能使用int來接收.
String sql = "SELECT name FROM user WHERE id = ?";
return jdbcTemplate.queryForObject(sql,String.class,id);
//需要注意的是:第一個參數(shù):SQL語句,第二個參數(shù):你查詢的結(jié)果的返回值類型,第三個參數(shù)是:你傳入的參數(shù)
queryForList()
在我們需要得到一個數(shù)據(jù)集合的時候,我們通常使用queryForList()進行。返回的結(jié)果是一個List<Map>結(jié)構(gòu)的集合。其中一個Map代表了一行數(shù)據(jù),使用列名作為key,使用值作為value。
并且queryForList()會默認(rèn)自動封裝。不需要手動進行數(shù)據(jù)封裝。
queryForMap()
queryForMap()是查詢一條數(shù)據(jù)的時候使用的封裝。將列名作為key,值作為value。封裝成一個map返回結(jié)果。
需要特別注意的是:因為queryForMap()是要求必須要有結(jié)果集的,如果查詢出的結(jié)果是null,則會報錯!如果不確定是否有結(jié)果集,請使用query()進行查詢,然后獲取數(shù)據(jù)。
query()
query()進行查詢的時候,必須自行對結(jié)果集進行取出并封裝。
優(yōu)點是:數(shù)據(jù)更加靈活,如果你想在結(jié)果集中加上一個固定值作為標(biāo)記,甚至自己自定義key的值,對value的值進行計算等等,都可以,非常靈活。
缺點是:你需要手動進行封裝數(shù)據(jù)。
代碼如下:
public Map queryById(Long id) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM user where 1=1");
List<Object> paramList = new ArrayList<>();
if (!StringUtils.isEmpty(id)) {
sql.append(" AND id = ? ");
paramList.add(id);
}
List<Map<String, Object>> query = this.jdbcTemplate.query(sql.toString(),
(rs, rowNum) -> {
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("name", rs.getString("name"));
dataMap.put("age", rs.getInt("age") + 100); //對查詢出來的結(jié)果進行計算,修改等等操作
dataMap.put("L3", 1); //我添加了一個固定列到結(jié)果集中
return dataMap;
}, paramList.toArray());
HashMap<Object, Object> map = new HashMap<>();
map.put("query",query);
return map;
}
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "age")
private int age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
結(jié)果:
{"query":[{"L3":1,"name":"zhsadsdfsn","age":156}]}