发表于: 2020-05-12 22:07:41
1 1200
最近忙完论文答辩,今天正式来线下试学。
今天完成的事情:了解jdbc,c3p0连接池
一.JDBC的API
1.DriverManager 驱动管理类
主要作用:
1.1注册驱动
实际开发中注册驱动会使用如下的方式:
Class.forName("com.mysq.jdbc.Driver");
//1.加载驱动
DriverManager.registerDriver(new Driver());
JDBC源代码中Driver类
但是在JDBC的Driver类中的静态代码块已经注册过了,再次如上手动调用会导致驱动注册两次。
1.2获得连接
Connection getConnection(String url,String username,String password);
url写法: jdbc:mysql://localhost:3306/jdbc <jdbc :协议 mysq|:子协议 localhost :主机名 3306 :端口号>
url简写: jdbc:mysq:///jdbc
2.Connection:连接对象
主要作用:
2.1创建执行SQL语句的对象,Connection三个方法
Statement createStatement : 执行SQL语句,有SQL注入的漏洞存在。
PreparedStatement prepareStatement(String sq) : 预编译SQL语句,解决SQL注入的漏洞。
CallableStatement prepareCall(String sql) : 执行SQL中存储过程
2.2进行事务的管理
setAutoCommit(boolean autoCommit) :设置事务是否自动提交。
commit() :事务提交
rollback() :事务回滚
3.Statement : 执行SQL
主要作用:
3.1执行SQL语句,不同返回值用不同的方法
boolean execute(String sql) :执行SQL ,执行select语句返回true,否则返回false
ResultSet executeQuery(String sq) :执行SQL中的select语句,查询
int executeUpdate(String sq|) :执行SQL中的insert/update/delete语句
3.2执行批处理操作,执行一批sql命令
addBatch(String sq) :添加到批处理
executeBatch() :执行批处理
clearBatch() :清空批处理
ResultSet :结果集
结果集:其实就是查询语句( select )语句查询的结果的封装。
主要作用:
结果集获取查询到的结果的。
next() :针对不同的类型的数据可以使用getXXX()获取数据,通用的获取数据的方法:
getObject();
4.jdbc的资源释放
jdbc程序运行结束后,要释放那些和数据库交互的对象,通常就是上面的,ResultSet,Statement和Connection.特别是Connection对象,它是特别稀有的资源,使用原则是晚创建,早释放。
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
conn = null;
}
二.JDBC的crud
/**
* JDBC的插入操作
*/
@Test
public void demo2(){
Connection conn = null;
Statement st =null;
try{
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获得连接
conn = DriverManager.getConnection("jdbc:mysql:///first","root","root");
//3.创建和执行语句
String sql = "insert into jdbctable values (4,'小四',24)";
st = conn.createStatement();
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
}catch(Exception e){
e.printStackTrace();
}finally{
//4.资源的释放
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
conn = null;//垃圾回收更早的回收对象
}
}
三.对JDBC的加载驱动和创建连接以及释放资源的公共代码提取成工具类,对参数生成properties文件并加载
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql:///first
username=root
password=root
public class JDBCUtils {
private static final String driverClass;
private static final String url;
private static final String username;
private static final String password;
static{
//加载属性文件,通常是类的加载器的方式进行获取
Properties props = new Properties();
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
props.load(is);
} catch (IOException e) {
e.printStackTrace();
}
driverClass = props.getProperty("driverClass");
url = props.getProperty("url");
username = props.getProperty("username");
password = props.getProperty("password");
}
/**
* 注册驱动的方法
* @throws ClassNotFoundException
*/
public static void loadDriver() throws ClassNotFoundException {
Class.forName(driverClass);
}
/**
* 获得连接
* @return conn
* @throws SQLException
*/
public static Connection getConnection() throws Exception {
loadDriver();
Connection conn = DriverManager.getConnection(url,username,password);
return conn;
}
public static void release(Connection conn, Statement st){
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
conn = null;
}
if(st != null){
try {
st.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
st = null;
}
}
public static void release(Connection conn, Statement st, ResultSet rs){
if(rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
rs = null;
}
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
conn = null;
}
if(st != null){
try {
st.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
st = null;
}
}
}
四.SQL注入漏洞,当应用在登录时,
在登录时,用户名aaa后面添加数据库的语句 aaa ' or '1=1 和 aaa' --
按照上面JDBC的statement方法,无论密码是多少都会通过,因为会把or判断前面是true,结果为true. --在SQL语句中为注释
解决SQL注入漏洞:运用PreparedStatement的使用:
PreparedStatement是Statement的子接口,它的实例对象可以通过调用
Connection.preparedStatement(sql)方法获得,相对于Statement对象而言:
- PreperedStatement可以避免SQL注入的问题。
- Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement可对SQL进行预编译,从而提高数据库的执行效率。
- 并且PreperedStatement对于sq|中的参数 ,允许使用占位符的形式进行替换,简化sq|语句的编写。
public class JDBCDemo5 {
/**
*删除数据
*/
@Test
public void demo(){
Connection conn = null;
PreparedStatement psmt = null;
try {
//获得连接
conn = JDBCUtils.getConnection();
//编写SQL
String sql = "delete from jdbctable where id = ?";
//预编译SQL
psmt = conn.prepareStatement(sql);
//设置参数
psmt.setInt(1,5);
//执行SQL
int num = psmt.executeUpdate();
if(num > 0){
System.out.println("运用prepareStatement删除成功!");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
JDBCUtils.release(conn,psmt);
}
}
}
五.c2p0连接池
连接池:连接池是创建和管理一个连接池的缓存池技术,这些连接准备好被任何所需要它们的线程使用。
应用程序直接获取连接的缺点:
用户每次请求都需要向数据库获取连接,而数据库创建连接通常会消耗大量资源。假如一个网站每天有10万的访问量,数据库服务器就需要创建10万次连接,极大的浪费的数据库资源,并且极容易造成数据库的内存溢出。
c3p0的使用:
导入c3p0的jar包
c3p0使用,可以手动设置参数
ComboPooledDataSource dataSource = ComboPooledDataSource(); //创建dataSource.getConnection();//获得连接池
dataSource.setMaxPoolSize(20)//最大连接数
dataSource.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver
dataSource.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
dataSource.setUser("swaldman");
dataSource.setPassword("test-password");
明天计划的事情:明天学习JdbcTemplate和mybatis。明天的速度还能再加快点。
遇到的问题:今天被自己一个小BUG卡了下,忘记获取对象,所以运行后一直报空指针异常
收获:今天算是记住了jdbc的运行过程。明天继续加油。
评论