使用JDBC操作数据库
JDBC获取连接的几种方式
- 通过Driver类还有properties对象获取连接
public static Connection test(){
try {
//注册驱动
Driver driver = new com.mysql.jdbc.Driver();
Properties info = new Properties();
info.setProperty("user","ck");
info.setProperty("password","spider@1314");
//获取连接
Connection connection = driver.connect(jdbcUrl,info);
return connection;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
- 使用Class.ForName加载Driver和读取配置文件的方式获取连接
public static Connection getConntion(){
Connection connection =null;
try {
//获取配置文件流
InputStream inputStream =ClassLoader.getSystemClassLoader()
.getResourceAsStream("jdbc.properties");
Properties properties = new Properties();
properties.load(inputStream);
Class.forName(properties.getProperty("driver"));
connection = DriverManager.getConnection(properties.getProperty("jdbcUrl")
,properties.getProperty("userName"),properties.getProperty("password"));
}catch (Exception e){
e.printStackTrace();
}
return connection;
}
这里需要解释一下,其实这里使用DriverManage之前其实是要注册驱动的
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
这边没有写是因为我们在使用Class.ForName加载Driver类的时候,Driver类中的静态代码块已经帮我实现了DriverManage的注册过程
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
使用JDBC进行通用的增删改查操作
- 使用jdbc联合preparedStatement实现通用增删改
public static void updataTable(String sql,Object ...args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
//使用工具类获取连接
connection = JDBCutil.getConntion();
//获取preparedStatement预编译SQL类
preparedStatement = connection.prepareStatement(sql);
//循环替换SQL中的变量值
for (int i = 0;i < args.length;i++){
preparedStatement.setObject(i+1,args[i]);
}
/**
* execute:方法执行的是查询语句,那么有结果集,返回true,如果是增删改那么就返回false
* executeUpdate:该方法会返回操作数据库的行数,大于零说明操作成功
* */
preparedStatement.executeUpdate();
}catch (SQLException e) {
e.printStackTrace();
}finally {
colseResoure(connection,preparedStatement);
}
- 使用jdbc和preparedStatement在联合反射实现通用的SQL查询
public static <T> List<T> selectTable(String sql , Class<T> clazz, Object ...args){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
//新建封装结果集的list
List<T> list = new ArrayList<T>();
try {
connection = getConntion();
preparedStatement = connection.prepareStatement(sql);
for (int i = 0;i < args.length;i++){
preparedStatement.setObject(i+1,args[i]);
}
resultSet = preparedStatement.executeQuery();
//返回结果集的元数据:ResultSetMeteData
ResultSetMetaData metaData = resultSet.getMetaData();
//获取列数
int columnCount = metaData.getColumnCount();
while (resultSet.next()){
//需要新建一个对象用来存储返回值
T t = (T)clazz.newInstance();
for (int i= 0 ;i < columnCount;i++){
Object columnValue = resultSet.getObject(i + 1);
/**
* 针对标的字段名和类的属性名不一样的时候应该使用的是表的别名
* String columnNmae = metaData.getColumnName(i + 1);
* */
String columnLabel = metaData.getColumnLabel(i + 1);
//使用反射原理将变量赋值给新建的对象
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columnValue);
}
list.add(t);
}
return list;
}catch (SQLException e){
e.printStackTrace();
}catch (InstantiationException e){
e.printStackTrace();
}catch (IllegalAccessException e){
e.printStackTrace();
}catch (NoSuchFieldException e){
e.printStackTrace();
}finally {
colseResoure(connection,preparedStatement,resultSet);
}
return null;
}
这里使用到了反射技术,因为在你数据的时候你不知道你获取到的数据到底是实体对象的哪一个属性,所以就需要使用到反射来进行为对象在代码运行的时候赋值
使用jdbc实现数据的批量操作
- 需要配合使用preparedStatement的addBatch,executeBatch,clearBatch方法
public static void batchUpdate(String sql,Object ...args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = getConntion();
//设置mysql为手动提交
connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement(sql);
for(int i = 0; i < 1000; i++ ) {
preparedStatement.setObject(1,"nimabo");
preparedStatement.addBatch();
if(i%100 == 0){
/**
* mysqlm默认是不支持Batch的盘批量操作的
* 需要给配置信息URL后边追加参数?rewriteBatchedStatement=true
* */
preparedStatement.executeUpdate();
preparedStatement.clearBatch();
}
}
//最后提交数据
connection.commit();
}catch (SQLException e) {
e.printStackTrace();
}finally {
colseResoure(connection,preparedStatement);
}
}
这里插一段有关statement和preparedStatement的区别
1)1.PreparedStatement继承自Statement,两者都是接口,内部都要建立类似于Sockt连接,效率都不是特别高。
2)当SQL特别多的时候,使用Statement,因为PrepareStatement的预编译空间有限,当数据量特别大时,会发生异常。
3)Statement拼接字符串的时候会出现SQL注入现象,PreparedStatement不会因为存在预编译,在注入参数前已经确定了SQL的逻辑结果
4)PreparedStatement还可以操作Blob类型的数据,操作数据范围比较广
JDBC的事务管理
1.事务的四个原则
1)原子性:处于一个事务中的DMLL操作要么都成功,要么都不成功
2)一致性:倘若事务操作失败,则回滚事务时,与原状态一致,即是一致性
3)隔离性:当你在操作时,其他事务的操作不能影响到你的事务操作,也就是事务与事务之间是隔离的,各干各的,互不干扰,干完在整合
4)持久性:事务操作的结果是具有持久性的,也就是事务一旦写入数据库,那再也不改动的情况下,数据库一直都是这个数据
2.jdbc的哪些操作为自动自交
1)数据库的DDL操作
2)数据库的DML默认是自动提价
3)默认关闭连接的饿时候,会自动提交
3.jdbc简单的实现事务
public static void main(String[] args) {
Connection connection = null;
try{
//从外部传入连接,最后一起关闭连接
connection = JDBCutil.getConntion();
//设置数据库为手动提交方式,等事务中的所有操作都完成了以后在提交
connection.setAutoCommit(false);
String sql = "UPDATE user_gp SET blanche = blanche-100 WHERE password=?";
JDBCutil.updataTable(sql,"aaa");
String sql2 = "UPDATE user_gp SET blanche = blanche+100 WHERE password=?";
JDBCutil.updataTable(sql2,"bbb");
connection.commit();
}catch (SQLException e){
e.printStackTrace();
try{
//当代码发生异常之后,需要回滚事务,保持原来之前的数据
connection.rollback();
}catch (SQLException e1){
e1.printStackTrace();
}
}finally {
try {
//需要设置为默认自动提交,如果连接没有关闭,其他事务使用了这个连接,那么默认就是手动提交了
connection.setAutoCommit(true);
}catch (SQLException e){
e.printStackTrace();
}
JDBCutil.colseResoure(connection,null);
}
}
接下来博主还会继续跟新有关JDBC的事务相关知识,学习是一个不断积累的过程,还希望大家可以一起努力,加油