Day29-JDBC增强

总结

我是最棒的!基础不牢,地动山摇!

JDBC增强

预编译对象PrepareStatement

在创建对象时就已经指定了模板(sql语句),使用占位符表示参数

例入插入语句

String sql = "insert into table values (?,?)";
//conn为连接对象,传入sql语句创建预编译对象
PreparedStatement pst = conn.prepareStatement(sql);

优点

  1. 提高代码可读性和可维护性
  2. 预编译的sql语句效率更高(需要数据库支持,但是mysql不支持),缓存机制
  3. 避免sql注入(非法sql语句)

预编译实现CRUD

package cn.itsource.preparedstatement.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


import cn.itsource.preparedstatement.dao.UserDao;
import cn.itsource.preparedstatement.domain.User;
import cn.itsource.util.JDBCUtil;

public class UserDaoImpl implements UserDao {

    //增
	@Override
	public void add(User user) {
		
		Connection connection = null;
		PreparedStatement pst = null;
		
		try {
			connection = JDBCUtil.getConnection();
			String sql = "insert into user values (null,?,?)";
			pst = connection.prepareStatement(sql);
			pst.setString(1, "byd");
			pst.setString(2, "hmp");
			
			pst.executeUpdate();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.close(connection, pst, null);
		}
	}

    //删
	@Override
	public void remove(Long id) {
		Connection conn = null;
		PreparedStatement pst = null;
		
		try {
			conn = JDBCUtil.getConnection();
			String sql = "delete from user where id = ?";
			pst = conn.prepareStatement(sql);
			pst.setLong(1, id);
			pst.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.close(conn, pst, null);
		}
	}

    //改
	@Override
	public void update(User user) {
		Connection conn = null;
		PreparedStatement pst = null;
		
		try {
			conn = JDBCUtil.getConnection();
			String sql = "update user set username = ?,password = ? where id = ?";
			pst = conn.prepareStatement(sql);
			pst.setString(1, user.getUsername());
			pst.setString(2, user.getPassword());
			pst.setLong(3, user.getId());
			
			pst.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.close(conn, pst, null);
		}
	}

    //查一个
	@Override
	public User getOne(Long id) {
		User user = null;
		Connection conn = null;
		PreparedStatement pst = null;
		ResultSet rs = null;
		
		try {
			conn = JDBCUtil.getConnection();
			String sql = "select * from user where id = ?";
			
			pst = conn.prepareStatement(sql);
			pst.setLong(1, id);
			rs = pst.executeQuery();
			
			if(rs.next()) {
				user = new User();
				user.setId(rs.getLong(1));
				user.setUsername(rs.getString(2));
				user.setPassword(rs.getString(3));
//				System.out.println(rs.getLong(1));
//				System.out.println(rs.getString(2));
//				System.out.println(rs.getInt(3));
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.close(conn, pst, rs);
		}
		return user;
	}

    //查所有
	@Override
	public List<User> getAll() {
		List<User> list = new ArrayList<User>();
		Connection conn = null;
		PreparedStatement pst= null;
		ResultSet rs = null;
		
		try {
			conn = JDBCUtil.getConnection();
			String sql = "select * from user";
			pst = conn.prepareStatement(sql);
			
			rs = pst.executeQuery();
			while(rs.next()){
				User user = new User();
				user.setId(rs.getLong(1));
				user.setUsername(rs.getString(2));
				user.setPassword(rs.getString(3));
				list.add(user);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return list;
	}

}

事务

事务在数据库中是指一组逻辑操作单元,为了保证数据中数据的一致性。就是一组相关的操作,他们必须同时成功,才算是成功。

Connection中的相关方法

//关闭自动提交,conn为Connection对象
Conn.setAutoCommit(false);
//手动提交
commit();
//如果在事务中发生异常,使用回滚,取消当前事务的所有操作
rollback();

转账事务

package cn.itsource.trancation;

import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.PreparedStatement;

import org.junit.Test;

import cn.itsource.util.JDBCUtil;

public class TxTest {

	@Test
	public void testTx() throws Exception {

		Connection conn = null;
		try {
			conn = JDBCUtil.getConnection();
			//关闭自动提交
			conn.setAutoCommit(false);
			
			String sql = "update account set money = money - 5000 where id = ?";
			PreparedStatement pst = conn.prepareStatement(sql);
			pst.setLong(1, 1L);
			pst.executeUpdate();
			
			//除0异常,模拟断电
			int i = 1/0;
			
			String sql2 = "update account set money = money + 5000 where id = ?";
			PreparedStatement pst2 = conn.prepareStatement(sql2);
			pst2.setLong(1, 2L);
			pst2.executeUpdate();
			//手动提交
			conn.commit();
		} catch (Exception e) {
			//发生异常,回滚
			conn.rollback();
		}		
	}
}

事务的四大特性(ACID)

  1. 原子性(Atomic)最小单位,一组事务是一个整体
  2. 一致性(Consistency)事务执行前,和执行后数据是守恒的,增加的和减少的一样多
  3. 隔离性(Isolation)多个不同的事务同时执行,相互之间不影响
  4. 持久性(Dirability)数据的修改或者更新必须同步保存到数据库中

我们通过修改事务的提交方式setAutoCommit(false)为手动来保证事务的原子性,一致性和持久性

获取主键

statement中的getGeneratedKeys()方法,在使用prepareStatement方法的时候将statement.RETURN_GENERATE_KEYS作为参数传入

连接池

反复地创建和销毁连接导致效率低下,资源利用率低

配置连接池的属性

  1. min最小连接数
  2. 新增连接数
  3. 超时时间
  4. max最大连接数

常见的连接池

JDK中有一个规范,DataSource接口(该接口用于从连接池获取连接对象),里面有getConnection()方法

DBCP

看官自行百度

C3P0

看官自行百度

Druid

重点掌握Druid,阿里巴巴开源的连接池,基于DBCP,性能最优

效率最高,最好的连接池,不接受反驳。

package cn.itsource.druid;

import static org.junit.Assert.*;

import java.sql.Connection;
import java.util.Properties;

import javax.sql.DataSource;

import org.junit.Test;

import com.alibaba.druid.pool.DruidDataSourceFactory;

public class DruidTest {
	@Test
	public void testDruid(){
		Properties p = new Properties();
		try {
			p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties"));
			DataSource dataSource = DruidDataSourceFactory.createDataSource(p);
			Connection conn = dataSource.getConnection();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

抽取相同部分的代码

将代码重复的部分抽取写一个模板类,类中有模板方法

package cn.itsource.template;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import cn.itsource.template.UserDaoImpl.UserHandler;
import cn.itsource.util.JDBCPoolUtil;

/**
 * 抽取DML与DQL的共同部分
 */
public class JDBCTemplate {
	/**
	 * DML的抽取
	 */
	public static void templateUpdate(String sql,Object... obj){
		Connection conn = JDBCPoolUtil.getConnection();
		PreparedStatement pst = null;
		
		try {
			pst = conn.prepareStatement(sql);
			for (int i = 0; i < obj.length; i++) {
				pst.setObject(i+1, obj[i]);
			}
			
			pst.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCPoolUtil.close(conn, pst, null);
		}
	}
	
	/**
	 * DQL的抽取
	 */
	public static<T> T templateQuery(String sql,IResultSetHandler<T> handler,Object... objs){
		Connection conn = JDBCPoolUtil.getConnection();
		PreparedStatement pst = null;
		ResultSet rs = null;
		try {
			pst = conn.prepareStatement(sql);
			for (int i = 0; i < objs.length; i++) {
				pst.setObject(i+1, objs[i]);
			}
			rs = pst.executeQuery();
			return handler.handler(rs);
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCPoolUtil.close(conn, pst, rs);
		}
		return null;
	}
}

自定义接口解决类型写死的问题

package cn.itsource.template;

import java.sql.ResultSet;

public interface IResultSetHandler <T>{
	T handler(ResultSet rs);
}

实现类

package cn.itsource.template;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import cn.itsource.preparedstatement.dao.UserDao;
import cn.itsource.preparedstatement.domain.User;
/**
 *	通过模板类,大大减少了我们的代码量
 */
public class UserDaoImpl implements UserDao {

	@Override
	public void add(User user) {
		String sql = "insert into user values (null,?,?)";
		JDBCTemplate.templateUpdate(sql, user.getUsername(),user.getPassword());
	}

	@Override
	public void remove(Long id) {
		String sql = "delete from user where id = ?";
		JDBCTemplate.templateUpdate(sql, id);
	}
	
	@Override
	public void update(User user) {
		String sql = "update user set username = ?,password = ? where id = ?";
		JDBCTemplate.templateUpdate(sql, user.getUsername(),user.getPassword(),user.getId());
	}

	@Override
	public User getOne(Long id) {
		String sql = "select * from user where id = ?";
		List<User> list = JDBCTemplate.templateQuery(sql, new UserHandler(),id);
		if(list != null){
			return list.get(0);
		}
		return null;
	}

	@Override
	public List<User> getAll() {
		String sql = "select * from user";
		List<User> list = JDBCTemplate.templateQuery(sql, new UserHandler());
		if(list != null){
			return list;
		}
		return null;
	}
	
	/**
	 * 内部类实现了自定义接口,用来处理User的结果集
	 * @author tyx666
	 *
	 */
	class UserHandler implements IResultSetHandler<List<User>>{

		@Override
		public List<User> handler(ResultSet rs) {
			List<User> list = new ArrayList<User>();
			try {
				while(rs.next()){
					User user = new User();
					user.setId(rs.getLong(1));
					user.setUsername(rs.getString(2));
					user.setPassword(rs.getString(3));
					list.add(user);
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return list;
		}
		
	}
}

猜你喜欢

转载自blog.csdn.net/t384061961/article/details/100718065