一、JDBC
传统的JDBC代码如下所示:
public static void main( String[] args )
{
Connection con = null; // 定义一个MYSQL链接对象
PreparedStatement ps = null; // 语句对象
ResultSet rs = null;
String sql = "SELECT * FROM country where id = ?;"; //sql语句,?为参数
try{
//加载Mysql驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取数据库连接对象
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?useSSL=false", "root", ""); // 链接本地MYSQL
//实例化PreparedStatement
ps = con.prepareCall(sql);
//设置参数
ps.setInt(1,1);
//执行sql
rs = ps.executeQuery();
//获取结果
if(rs.next()){
System.out.println(rs.getString(2));
}
}catch (ClassNotFoundException | SQLException e){
e.printStackTrace();
}finally {
//释放资源
try {
if (ps != null) ps.close();
if (con != null) con.close();
if (rs != null) rs.close();
} catch (SQLException ignored) {
}
}
}
操作数据库的传统方式是通过JDBC实现,如上述代码,我们实现一个查询数据库的操作。上述代码核心的其实只有一句:ps = con.prepareCall(sql); 其他的语句如加载数据库驱动、连接数据库、执行查询以及释放资源等操作都是模板代码,编写这些完全相同的代码,是对时间的浪费。
二、Spring中的JDBC
上述使用传统JDBC操作数据库时,包含了大量与业务无关但又必须的代码。 Spring JDBC 通过模板和回调机制大大降低了使用JDBC 的复杂度,借由JdbcTemplate 的帮助,仅需要编写那些"必不可少"的代码就可以进行数据库操作。
一般情况下都是在DAO类中使用JdbcTemplate, JdbcTemplate 在XML配置文件中配置好后,直接在DAO 中注入即可。
2.1 示例:
1)创建与数据库表Country对应的类对象:
public class Country {
private int id;
private String countryName;
private String countryCode;
public int getId() {
return id;
}
public String getCountryName() {
return countryName;
}
public String getCountryCode() {
return countryCode;
}
public void setId(int id) {
this.id = id;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
}
2)创建CountryDao接口,该接口规定了对数据库的操作
public interface CountryDao {
/**
* 新增一条用户
*
* @param country
* @return
*/
int addUer(Country country);
/**
* 更新指定的用户信息
*
* @param country
* @return
*/
int update(Country country);
/**
* 删除指定的信息
*
* @param country
* @return
*/
int delete(Country country);
/**
* 统计用户个数
*
* @param country
* @return
*/
int count(Country country);
/**
* 查询用户列表
*
* @param
* @return
*/
List<Country> getList();
/**
* 查询单个用户信息
*
* @param country
* @return
*/
Country getUser(Country country);
/**
* 批量增加
*
* @param batchArgs
*/
void batchAddCountry(List<Object[]> batchArgs);
}
3)创建CountryDao接口的实现类CountryDaoImpl:
public class CountryDaoImpl implements CountryDao{
private JdbcTemplate jdbcTemplate; //属性,由Spring注入
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public int addUer(Country country) {
String sql = "INSERT INTO `country`(countryname,countrycode) VALUES(?,?);";
int update = jdbcTemplate.update(sql,country.getCountryName(),country.getCountryCode());
return update;
}
@Override
public int update(Country country) {
String sql = "UPDATE country SET countryname = ?,countrycode=?\n" +
"WHERE id = ?;";
int update = jdbcTemplate.update(sql,country.getCountryName(),country.getCountryCode(),country.getId());
return update;
}
@Override
public int delete(Country country) {
String sql = "DELETE from country WHERE id = ?;";
int update = jdbcTemplate.update(sql,country.getId());
return update;
}
@Override
public int count(Country country) {
String sql ="SELECT COUNT(*) FROM country;";
int count = jdbcTemplate.queryForObject(sql,Integer.class);
return count;
}
@Override
public List<Country> getList() {
String sql = "SELECT * FROM country;";
List<Country> countryList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Country>(Country.class));
return countryList;
}
@Override
public Country getUser(Country country) {
String sql = "SELECT * FROM country WHERE id = ?;";
Country country1 = jdbcTemplate.queryForObject(sql, new RowMapper<Country>() {
@Override
public Country mapRow(ResultSet resultSet, int i) throws SQLException {
Country country2 = new Country();
country2.setId(resultSet.getInt("id"));
country2.setCountryName(resultSet.getString("countryname"));
country2.setCountryCode(resultSet.getString("countrycode"));
return country2;
}
}, country.getId());
return country1;
}
@Override
public void batchAddCountry(List<Object[]> batchArgs) {
}
}
我们可以看到,在创建的DAO类中,包含一个JdbcTemplate属性,所有数据库的增、删、查、改及存储过程等操作, 都是通过JdbcTemplate 提供的众多方法实现的。
Spring框架中,我们可以通过XML配置文件配置好JdbcTemplate ,然后直接在DAO 中注入即可。
4)配置文件配置JdbcTemplate:
DriverManagerDataSource数据源配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 属性注入 -->
<!-- 数据库驱动 -->
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<!-- 连接数据库url -->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"></property>
<!-- 数据库名称 -->
<property name="username" value="root"></property>
<!-- 数据库密码 -->
<property name="password" value="root"></property>
</bean>
<!-- 配置jdbc模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 配置数据源属性 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="countryDao" class="com.wyf.springjdbc.CountryDaoImpl">
<!-- 注入属性 -->
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
</beans>
C3P0数据源配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置数据源 -->
<!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">-->
<!-- <!– 属性注入 –>-->
<!-- <!– 数据库驱动 –>-->
<!-- <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>-->
<!-- <!– 连接数据库url –>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"></property>-->
<!-- <!– 数据库名称 –>-->
<!-- <property name="username" value="root"></property>-->
<!-- <!– 数据库密码 –>-->
<!-- <property name="password" value="wyfroot"></property>-->
<!-- </bean>-->
<!-- 配置数据源(C3P0) -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<!-- 属性注入 -->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"></property>
<property name="user" value="root"></property>
<property name="password" value="wyfroot"></property>
<!-- C3P0其他属性设置 -->
<!--连接池中保留的最小连接数。 -->
<property name="minPoolSize" value="10" />
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize" value="100" />
<!--最大空闲时间,1800秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime" value="1800" />
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement" value="3" />
<property name="maxStatements" value="1000" />
<property name="initialPoolSize" value="10" />
<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod" value="60" />
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts" value="30" />
<property name="breakAfterAcquireFailure" value="true" />
<property name="testConnectionOnCheckout" value="false" />
</bean>
<!-- 配置jdbc模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 配置数据源属性 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="countryDao" class="com.wyf.springjdbc.CountryDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
</beans>
5)测试代码
@Test
public void JdbcTemplateTest2(){
ApplicationContext context = new ClassPathXmlApplicationContext("Bean.xml");
CountryDaoImpl countryDao = (CountryDaoImpl)context.getBean("countryDao");
Country country = new Country();
country.setId(17);
country.setCountryName("CUBA");
country.setCountryCode("CU");
System.out.println("查询数量:"+countryDao.count(country));
System.out.println("插入一条数据:"+countryDao.addUer(country));
country.setCountryCode("FJ");
country.setCountryName("Fiji");
System.out.println("更改数据:"+countryDao.update(country));
Country country_t = countryDao.getUser(country);
System.out.println("获取到的对象名称:"+country_t.getCountryName());
List<Country> countryList = countryDao.getList();
System.out.println("获取到的对象数量:"+countryList.size());
}
2.2 RowMapper
使用JDBC从数据库查询数据时,查询出来的结果都被记录在ResultSet结果集中,而在Java程序中,我们需要获取结果集中一条条数据,并对应到具体的JavaBean上(ORM思想)。然而,数据库表中的字段和JavaBean类中的属性应该如何对应呢?RowMapper接口可以为我们解决这个问题。
如下所示,将ResultSet查询到的数据和JavaBean对应起来:
@Override
public Country getUser(Country country) {
String sql = "SELECT * FROM country WHERE id = ?;";
Country country1 = jdbcTemplate.queryForObject(sql, new RowMapper<Country>() {
@Override
public Country mapRow(ResultSet resultSet, int i) throws SQLException {
Country country2 = new Country();
country2.setId(resultSet.getInt("id"));
country2.setCountryName(resultSet.getString("countryname"));
country2.setCountryCode(resultSet.getString("countrycode"));
return country2;
}
}, country.getId());
return country1;
}
BeanPropertyRowMapper类:
BeanPropertyRowMapper类是RowMapper的一个实现类,它可以自动将一行数据映射到指定类的实例中,它首先将这个类实例化,然后通过名称匹配的方式,映射到属性中去,如果某个属性不匹配则返回属性值为Null。
这种自动绑定的方式,需要列名称和Java实体类中属性名称一致。所以,如果在使用时,Java类名称要想和数据库字段名称匹配上,必须要把数据库字段名称设计成以下两种中的一种:
- 数据库字段名设计成全小写的形式,如myname;
- 数据库字段名设计成下划线分割的形式,如my_name;
同时,Java属性名称应该尽量遵循Java编码风格,使用camelCase风格,如myName。如果数据中列名和属性名不一致,在sql语句中需要用as重新取一个别名。
示例代码如下:
public List<Country> getList() {
String sql = "SELECT * FROM country;";
List<Country> countryList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Country>(Country.class));
return countryList;
}
public Country getUser(Country country) {
String sql = "SELECT * FROM country WHERE id = ?;";
// Country country1 = jdbcTemplate.queryForObject(sql, new RowMapper<Country>() {
// @Override
// public Country mapRow(ResultSet resultSet, int i) throws SQLException {
// Country country2 = new Country();
// country2.setId(resultSet.getInt("id"));
// country2.setCountryName(resultSet.getString("countryname"));
// country2.setCountryCode(resultSet.getString("countrycode"));
// return country2;
// }
// }, country.getId());
Country country1 = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Country>(Country.class),country.getId());
return country1;
}