1.背景介绍
按照任务步骤学习了JDBC,以及JDBCTemplate,总结一下两者之间的联系与区别
2.知识剖析
什么是JDBC
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API它由一组用Java语言编写的类和接口组成。
DBC API提供了以下接口和类:
DriverManager: 这个类管理数据库驱动程序的列表。确定内容是否符合从Java应用程序使用的通信子协议正确的数据库驱动程序的连接请求。识别JDBC在一定子协议的第一个驱动器将被用来建立数据库连接。
Driver: 此接口处理与数据库服务器通信。很少直接直接使用驱动程序(Driver)对象,一般使用DriverManager
中的对象,它用于管理此类型的对象。它也抽象与驱动程序对象工作相关的详细信息
Connection : 此接口与接触数据库的所有方法。连接对象表示通信上下文,即,与数据库中的所有的通信是通过此唯一的连接对象。
Statement : 可以使用这个接口创建的对象的SQL语句提交到数据库。一些派生的接口接受除执行存储过程的参数。
ResultSet: 这些对象保存从数据库后,执行使用Statement
对象的SQL查询中检索数据。它作为一个迭代器,可以通过移动它来检索下一个数据。
SQLException: 这个类用于处理发生在数据库应用程序中的任何错误。
JDBC 可做三件事:与数据库建立连接、发送 操作数据库的语句并处理结果
JDBC访问数据库的一般步骤
1与数据库建立连接
2创建SQL语句
3获得用于向数据库发送sql语句的对象
Statement statement = connection.createStatement()
PreparedStatement preparedStatement=connection.preparStatement(sql)
4执行SQL语句
executeQury用于执行SELECT语句,返回代表结果的ResultSet对象
executeUpdate用于INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE
返回一个整数(int)用于指示受影响的行数
execute可执行任何sql语句,返回一个boolean值,表明执行该SQL语句是否返回了ResultSet
5关闭连接,释放资源
先关闭resultSet,再statement,最后是connection,通过if和try catch语句确保资源释放
public class JDBCUtils {
// 数据库 URL
private static String url = "jdbc:mysql://localhost:3306/task2";
// 数据库的用户名与密码
private static String user = "";
private static String password = "";
//无参构造方法初始化类
private JDBCUtils() {
}
static {
try {
//加载Jdbc驱动
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//通过调用此方法建立连接
public static Connection getConnection() throws SQLException {
return (Connection) DriverManager.getConnection(url, user, password);
}
//释放资源的方法,通过调用避免代码的繁琐
public static void free(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) {
try {
//关闭连接
if (resultSet != null)
resultSet.close();
//如果出现异常交jvm处理,并将错误打印到控制台
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (preparedStatement != null)
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (connection != null)
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
public class UserDAOImpl implements UserDAO {
// 需要学习的获得更改表的时间
// s1.setUpdate_at(System.currentTimeMillis()/1000);
// 初始化变量
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
//重写父类方法,实现insert具体操作
public int insert(User user) {
// TODO Auto-generated method stub
// 初始化返回行数
int row = 0;// 影响的行数,返回0表示插入失败,返回1表示插入成功
// try catch 方法用于捕获异常,和处理在解决范围的异常
try {
// 建立与数据库的连接
connection =JDBCUtils.getConnection();
String sql = "INSERT INTO user1 VALUES(?,?,?,?)";
// 创建预编译执行语句,先编译再一起执行
preparedStatement = connection.prepareStatement(sql);
// 通过调用,preparedStatement的set方法确定values后面具体的字段名,避免参数的混乱
preparedStatement.setObject(1, user.getId());
preparedStatement.setObject(2, user.getName());
preparedStatement.setObject(3, user.getPassword());
preparedStatement.setObject(4, user.getBirth());
// executeUpdate方法会返回受影响行数,已确定是否插入成功
row = preparedStatement.executeUpdate();
//如果不能建立连接就会catch异常,并打印到输出台中
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
JDBCUtils.free(resultSet, preparedStatement, connection);
}
return row;
}
//根据id查询
public int update(User user) {
// TODO Auto-generated method stub
int row = 0;
try {
connection = JDBCUtils.getConnection();
String sql = "UPDATE user1 SET name = ?,password = ?, birth = ? WHERE id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setObject(1, user.getName());
preparedStatement.setObject(2, user.getPassword());
preparedStatement.setObject(3, user.getBirth());
preparedStatement.setObject(4, user.getId());
row = preparedStatement.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
JDBCUtils.free(resultSet, preparedStatement, connection);
}
return row;
}
//根据id删除
public int delete(int userId) {
// TODO Auto-generated method stub
int row = 0;
try {
connection =JDBCUtils.getConnection();
String sql = "DELETE FROM user1 WHERE id =?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setObject(1, userId);
row = preparedStatement.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
JDBCUtils.free(resultSet, preparedStatement, connection);
}
return row;
}
//根据id查询
public User queryById(int userId) {
User user = new User();
try {
connection = JDBCUtils.getConnection();
String sql = "SELECT * FROM user1 WHERE id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setObject(1, userId);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
user.setId(resultSet.getInt(1));
user.setName(resultSet.getString(2));
user.setPassword(resultSet.getString(3));
user.setBirth(resultSet.getString(4));
}
} catch (SQLException e) {
e.printStackTrace();
}
finally {
JDBCUtils.free(resultSet, preparedStatement, connection);
}
return user;
}
//查询整个表
public List<User> queryAll() {
// 通过多态创建list类型的ArrayList对象实例
List<User> users = new ArrayList<User>();
User user = null;
// TODO Auto-generated method stub
try {
connection =JDBCUtils.getConnection();
String sql = "SELECT * FROM user1";
preparedStatement = connection.prepareStatement(sql);
// executeQuery方法返回代表查询结果集的resultSet对象
resultSet = preparedStatement.executeQuery();
// 遍历整个结果集
while (resultSet.next()) {
user = new User();
user.setId(resultSet.getInt(1));
user.setName(resultSet.getString(2));
user.setPassword(resultSet.getString(3));
user.setBirth(resultSet.getString(4));
// 对于每行结果集的列都通过集合方法添加进user对象
users.add(user);
// System.out.println(users);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
JDBCUtils.free(resultSet, preparedStatement, connection);
}
return users;
}
//批量插入
public void insertBatch(User user) {
try {
connection = JDBCUtils.getConnection();
String sql = "insert into User1 values (?,?,?,?)";
preparedStatement = connection.prepareStatement(sql);
connection.setAutoCommit(false);
for (int i = 0; i < 1000000; i++) {
preparedStatement.setObject(1, user.getId());
preparedStatement.setObject(2, user.getName());
preparedStatement.setObject(3, user.getPassword());
preparedStatement.setObject(4, user.getBirth());
preparedStatement.addBatch();
if (i%1000==0){
preparedStatement.executeBatch();}
}
preparedStatement.executeBatch();
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}
finally {
JDBCUtils.free(resultSet, preparedStatement, connection);
}
}
public static void main(String[] args) {
UserDAO userDAO=new UserDAOImpl();
long start=System.currentTimeMillis();
for (int i = 390867; i < 1390867; i++) {
System.out.println(userDAO.queryById(i));
}
long end=System.currentTimeMillis();
System.out.println(end-start);
}
}
什么是JDBC Template
为了使 JDBC 更加易于使用,Spring 在 JDBCAPI 上定义了一个抽象层, 以此建立一个JDBC存取框架,通俗点说就是Spring对jdbc的封装的模板。在配置文件中使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中
1.xml配置文件
在配置文件中创建dataSource的bean注入相关属性,然后将定义好的DataSource注入到jdbcTemplate中
2执行SQL语句
execute方法可以用于执行任何SQL语句,一般用于执行DDL语句
update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句
query方法及queryForXXX方法:用于执行查询相关语句
call方法:用于执行存储过程、函数相关语句
3两者对比
Spring提供的JdbcTemplate对jdbc做了封装,大大简化了数据库的操作如果直接使用JDBC的话,需要我们加载数据库驱动、创建连接、释放连接、异常处理等一系列的动作;繁琐且代码看起来不直观。此外,Spring提供的JdbcTempate能直接数据对象映射成实体类,不再需要获取ResultSet去获取值/赋值等操作,提高开发效率
实现类
//通过传入id删除对应得行的列
public void delete(int i) {
String sql = "delete from user where id=?";
jdbcTemplate.update(sql, i);
}
//通过传入user对应得id修改name字段
public void update(User user) {
String sql = "update user set name=? where id=?";
Object objects[] = new Object[]{user.getName(), user.getId()};
jdbcTemplate.update(sql, objects);
}
//通过id查询本行列的所有信息
public User selectById(int i) {
String sql = "select * from user where id=?";
User u = jdbcTemplate.queryForObject(sql, new UserRowMapper(), i);
return u;
}
//查询整个表格
public List<User> selectAll() {
String sql = "select * from user ";
List<User> L = jdbcTemplate.query(sql, new UserRowMapper());
return L;
}
class UserRowMapper implements RowMapper<User> {
/**
* rs:结果集.
* rowNum:行号
*/
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User r = new User();
r.setId(rs.getInt("id"));
r.setSex(rs.getString("sex"));
r.setName(rs.getString("name"));
r.setAddress((rs.getString("address")));
return r;
}
}
}
<!-- 导入资源文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:db.properties"></property>
</bean>
<!-- 1.将连接池放入spring容器 -->
<bean id="DataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${user}"></property>
<property name="password" value="123"></property>
</bean>
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="DataSource"></property>
</bean>
3.常见问题
3.1sql语句报错
3.2连接数据库后没有关闭连接
3.3连接数过多,加载过慢
4.解决方案
4.1检查基本sql语句是否正确,检查执行sql语句参数的先后顺序,在preparesStatement.setObject中应与sql语句相匹配
4.2不关闭连接是一种资源的浪费,如果调用多次,到后面可能就会没有连接资源,导致连接不上数据库,执行完操作需要释放资源
4.3配置连接池
5.扩展思考
通过学习spring再创建一个bean用于注入jdbcTemplate
可通过spring的ioc生产一个对象去调用方法
建立连接池
能让连接得到循环调用
6.参考文献
https://www.cnblogs.com/qiuyong/p/6363224.html
https://www.cnblogs.com/erbing/p/5805727.html
https://blog.csdn.net/u013468917/article/details/52217954
https://blog.csdn.net/m_hahahaha1994/article/details/51752370