SpringBoot:使用JdbcTemplate

什么是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)- {}平臺的.sql和數(shù)據(jù) {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("別名")來獲取.

可能遇到的錯:


image.png

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}]}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容