【JavaWeb】-mysql、jdbc、dbcp使用(二),看完你还不会吗

24 篇文章 6 订阅
10 篇文章 0 订阅

JavaWeb

前言

前情回顾:【JavaWeb】-Tomcat、Eclipse使用项目搭建(一):https://blog.csdn.net/hello_list/article/details/124343254
在这里插入图片描述

如果你直接看大这篇文章还没进行环境搭建,可以回到第一篇搭建下环境,这样就可以完成这一部分我们对代码的操作;

需要得基础:会sql语句,基本的增删改查;

这里MySql没有说,后面有机会给大家出一个完整的mysql的知识点;看到这里希望可以给博主点个赞哦!

mysql

官网:https://www.mysql.com/

不过多介绍了,看下百度百科的介绍吧:

在这里插入图片描述

下载安装

在这里插入图片描述

我们使用mysql8
在这里插入图片描述

选择安装包:

在这里插入图片描述

在这里插入图片描述

这里就不带着大家安装了,网上教程很多,安装一个软件嘛,不过这里还是看着别人的图文教程一步步走比较好,现在马上去搜索一个安装教程,安装完后马上回来哦!

再说一下,万事开头配置难,配好一个环境对开发很重要,并且在配置环境的时候可能会出各种错,如果解决不了,大家换mysql版本,多重装几次,一定可以的

navicat

navicat是用来管理数据的一个可视化工具:我们不想用命令行一直在操作mysql,所以我们使用一个可视化工具更方便管理数据库;

当然这个软件是收费的,我们可以破解一下,这里大家也可以使用别的可视化工具,sqlyog都可以;

这里还是不带着大家安装了,教程很多,很简单大家快去安装上,这里给大家方便,随便找了一个教程,还是那句话,都不难很简单,快去安装完回来:http://t.zoukankan.com/yudx-p-13522514.html

JDBC

你回来了,那么我们就正式进入JDBC的学习了,什么是JDBC,来自百度百科:

在这里插入图片描述

其实就是java操作数据库的规范,我们知道关系型数据库有很,比如sqlserver 、mysql等等,但是不同的数据库我们不能去学很多种操作吧,这个时候为方便就可以规定了jdbc协议,我们使用不同的数据库,只需要切换数据源就可以,操作规范都是一样的,当然就省事了;

那对于Jdbc我们学习这么几个,连接数据库,操作数据库,断开数据库,直接上代码,连接数据库:

环境准备

在使用jdbc之前我们首先引入mysql驱动依赖:

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

数据库表,我这里创建了一张货物表(Good):

/*
Navicat MySQL Data Transfer

Source Server         : 本机
Source Server Version : 80011
Source Host           : localhost:3306
Source Database       : huanying

Target Server Type    : MYSQL
Target Server Version : 80011
File Encoding         : 65001

Date: 2022-04-20 17:36:09
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for good
-- ----------------------------
DROP TABLE IF EXISTS `good`;
CREATE TABLE `good` (
  `goodid` int(20) NOT NULL,
  `goodname` varchar(20) NOT NULL,
  `surplus` int(20) NOT NULL,
  `goodprice` int(20) NOT NULL,
  PRIMARY KEY (`goodid`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of good
-- ----------------------------
INSERT INTO `good` VALUES ('1', '黑色森林', '2', '15');
INSERT INTO `good` VALUES ('2', '奶油蛋糕', '3', '13');
INSERT INTO `good` VALUES ('3', '水果蛋糕', '2', '11');
INSERT INTO `good` VALUES ('4', '冰淇凌蛋糕', '5', '13');
INSERT INTO `good` VALUES ('9', '牛奶蛋糕', '34', '9');
INSERT INTO `good` VALUES ('11', '肉松蛋糕', '13', '13');

查询操作

package dao;

import java.sql.*;

public class TesterDao {
	public static void main(String[] args) {
		// 四大属性
		String DRIVER = "com.mysql.jdbc.Driver";
		String URL = "jdbc:mysql://localhost:3306/huanying?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8";
		String NAME = "root";
		String PASSWORD = "root";

		// 三大对象
		Connection con = null; // 连接对象
		PreparedStatement ps = null; // sql语句编译对象
		ResultSet rs = null; // 返回结果集,查询对象

		// 连接mysql
		try {
			Class.forName(DRIVER);
			con = DriverManager.getConnection(URL, NAME, PASSWORD);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}

		// 编译sqly语句,
		String sql = "select * from good";

		try {
            //con.createStatement()  这个不安全,不使用
			// 从数据库连接中获取sql语句
			ps = con.prepareStatement(sql);
			// 执行sql,并返回结果集,查询使用executeQuery,增删改使用executeUpdate
			rs = ps.executeQuery();

			// 便利取出结果集内容
			while (rs.next()) {
				System.out.println(rs.getInt(1)); // 从第一列返回
				System.out.println(rs.getString(2)); // 从第二列返回
				System.out.println(rs.getInt(3)); // 从第三列返回
				System.out.println(rs.getInt(4)); // 从第四列返回
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		// 最后关闭连接,从123=》321这个顺序关闭
		try {
			if (rs != null) {
				rs.close();
			}
			if (ps != null) {
				ps.close();
			}
			if (con != null) {
				con.close();
			}
		} catch (Exception e) {
		}

	}
}

结果

在这里插入图片描述

增删改操作

修改我们只需要改变一个地方就可以,1、连接数据库,2、执行sql,返回结果,3、关闭连接,这里我们主要做第三步

package dao;

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

public class Test02Dao {
	public static void main(String[] args) {
		// 四大属性
		String DRIVER = "com.mysql.jdbc.Driver";
		String URL = "jdbc:mysql://localhost:3306/huanying?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8";
		String NAME = "root";
		String PASSWORD = "root";

		// 三大对象
		Connection con = null; // 连接对象
		PreparedStatement ps = null; // sql语句编译对象
		ResultSet rs = null; // 返回结果集,查询对象

		// 连接mysql
		try {
			Class.forName(DRIVER);
			con = DriverManager.getConnection(URL, NAME, PASSWORD);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}

		// 编译sql语句,添加一条数据
		String sql = "insert into good values(12,'草莓蛋糕',22,23)";

		try {
			// 从数据库连接中获取sql语句
			ps = con.prepareStatement(sql);
			// 执行sql,并返回结果集,查询使用executeQuery,增删改使用executeUpdate
			//增删改只返回影响数据库行数,int类型
            //删改都一样,尝试下
			int result = ps.executeUpdate();

			if (result==1) {
				System.out.println("添加数据成功");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		// 最后关闭连接,从123=》321这个顺序关闭
		try {
			if (rs != null) {
				rs.close();
			}
			if (ps != null) {
				ps.close();
			}
			if (con != null) {
				con.close();
			}
		} catch (Exception e) {
		}

	}
}

运行结果

在这里插入图片描述

sql预编译

那我们知道,这样写的sql语句是死的,但是如果靠字符串拼接,那就很不安全,这里我们可以实现sql预编译,通过?去充当占位符那样,这里我们使用修改尝试下

package dao;

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

public class Testr03Dao {
	public static void main(String[] args) {
		// 四大属性
		String DRIVER = "com.mysql.jdbc.Driver";
		String URL = "jdbc:mysql://localhost:3306/huanying?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8";
		String NAME = "root";
		String PASSWORD = "root";

		// 三大对象
		Connection con = null; // 连接对象
		PreparedStatement ps = null; // sql语句编译对象
		ResultSet rs = null; // 返回结果集,查询对象

		// 连接mysql
		try {
			Class.forName(DRIVER);
			con = DriverManager.getConnection(URL, NAME, PASSWORD);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}

		// 编译sql语句,添加一条数据
		String sql = "update good set surplus=? where goodid=?";
		
		//两个从前台获取的值
		int surplus=99;
		int goodid=12;
		
		
		try {
			// 从数据库连接中获取sql语句
			ps = con.prepareStatement(sql);
			//补充完sql 
			ps.setObject(1, surplus);   //点一下,有很多set类型的方法object更好用,两个参数:从左开始第几个?,填充什么值
			ps.setObject(2, goodid);
			
			// 执行sql,并返回结果集,查询使用executeQuery,增删改使用executeUpdate
			//增删改只返回影响数据库行数,int类型
			int result = ps.executeUpdate();

			if (result==1) {
				System.out.println("修改数据成功");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		// 最后关闭连接,从123=》321这个顺序关闭
		try {
			if (rs != null) {
				rs.close();
			}
			if (ps != null) {
				ps.close();
			}
			if (con != null) {
				con.close();
			}
		} catch (Exception e) {
		}

	}
}

运行结果

在这里插入图片描述

DBCP

介绍

来自百度百科:

在这里插入图片描述

dbcp大家不要多想就是一个池化概念,什么操作都没有,就是在jdbc的基础上多了些配置;

池化技术,百度百科介绍的很清楚,这里我在给大家比喻一下,好比你从一个房间进出,你需要不停的开关门,进出很多次是不是很烦,麻烦对不对,这个时候如果我们一直把门打开这,这样进出不就很方便,门卫,对吧,他会自己去管理这门什么时候关什么时候一直开着,所以就很方便,不理解没关系,不妨碍我们使用;

环境改变

想要使用dbcp需要导入dbcp的三个jar包:

commons-pool2-2.4.2.jar,commons-logging-1.2.jar,commons-dbcp2-2.1.1.jar

maven依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>${dbcp.version}</version>
</dependency> 

创建一个配置文件,db.properties文件用来放置配置文件,这个是在网上找的比较全点

#全部的参数参考,org.apache.commons.dbcp2.BasicDataSourceFactory里的ALL_PROPERTIES
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/huanying?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8
username=root
password=
 
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000

#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=gbk;serverTimezone=UTC
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

创建DBCPUtil工具类:

package dao;


import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

// 封装Dbcp连接池的工具类
// 该类中提供了获取连接和关闭连接的通用方法
public class DbcpUtil {
	// 使用ThreadLocal来解决线程同步问题.让每个线程都使用各自的连接对象
	// ThreadLocal<Connection> 可以被其中的Connection做成多份拷贝,让不同的线程对象使用
	private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
	private static DataSource ds;

	// 静态代码块会在程序执行之前,被自动的执行
	static {
		InputStream in = DbcpUtil.class.getResourceAsStream("db.properties");
		Properties pro = new Properties();
		try {
			pro.load(in);
			ds = BasicDataSourceFactory.createDataSource(pro);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {

			e.printStackTrace();
		}
	}

	// 获取连接的时候,把方法中遇到的异常通过throws抛出去,抛给调用者
	// 通过异常在方法和方法之间传递信息
	public static Connection getConnectio() throws SQLException {
		Connection conn = threadLocal.get();
		// 如果conn等于null 或者conn已经关闭
		if (conn == null || conn.isClosed()) {
			conn = ds.getConnection();
			threadLocal.set(conn);
		}
		return conn;
	}

	public static void closeConnection() {
		Connection conn = threadLocal.get();
		try {
			// 如果conn不等于null 并且没有关闭
			if (conn != null && !conn.isClosed()) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			threadLocal.set(null);
		}
	}

}

查询数据库

package dao;

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

public class DBCPTester01 {
	public static void main(String[] args) {

		// 三大对象
		Connection con = null; // 连接对象
		PreparedStatement ps = null; // sql语句编译对象
		ResultSet rs = null; // 返回结果集,查询对象

		try {
			// 1、获取连接对象,改变了
			con = DbcpUtil.getConnectio();

			// 2、执行sql语句
			// 编译sql语句,
			String sql = "select * from good";

			// 从数据库连接中获取sql语句
			ps = con.prepareStatement(sql);
			// 执行sql,并返回结果集,查询使用executeQuery,增删改使用executeUpdate
			rs = ps.executeQuery();

			// 便利取出结果集内容
			while (rs.next()) {
				System.out.println(rs.getInt(1)); // 从第一列返回
				System.out.println(rs.getString(2)); // 从第二列返回
				System.out.println(rs.getInt(3)); // 从第三列返回
				System.out.println(rs.getInt(4)); // 从第四列返回
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//最后关闭连接,这里的关闭不是像jdbc直接关闭了连接,而是放回来连接池
			DbcpUtil.closeConnection();
		}

	}
}

运行结果

在这里插入图片描述

我们发现知识配置一下,知识获得连接和关闭连接的方式变了,其他都没变,很简单吧,主要就是理解其中的概念;

BaseDao

我们发现是不是操作数据库总共分三步:1、连接mysql 2、执行sql语句 3、关闭数据库,我们发现其实只有第二步是我们一直使用在改变的,第一步和第三步,完全没有必要每次写那么多代码,我们都是学过面向对象的人了,那我们就可以对这个进行下简单的封装;

对于增删改方法,我们发现PreparedStatement对象都是执行的executeUpdate方法,那就简单了,增删改我们封装到一个方法里:

public int executeUpdate(String sql, Object... param) {
    int result = 0;
    try {
        // 通过DBCP获取连接
        con = DbcpUtil.getConnectio();

        ps = con.prepareStatement(sql);
        for (int i = 0; i < param.length; i++) {
            ps.setObject(i, param[i]);
        }
        result = ps.executeUpdate();
    } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        DbcpUtil.closeConnection();
    }
    return result;
}

但是对于查询方法的封装,对于每张表都不一样,通过sql查询的结果也都不一样,所以我们封装到sql执行把ResultSet结果集对象交出给自定义处理:

public ResultSet executeQuery(String sql, Object... param) {
		try {
			con = DbcpUtil.getConnectio();
			ps = con.prepareStatement(sql);
			if (param != null) {
				for (int i = 0; i < param.length; i++) {
					ps.setObject(i++, param[i]);
				}
			}
			rs = ps.executeQuery();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return rs;
	}

为什么这里我没有关闭连接呢,你尝试下,是不是就报错了,因为数据都在ResultSet对象里,如果我们关闭连接就是ResultSet关闭,当然会报错,并且数据取不出来;

在这里插入图片描述

最后完整的BaseDao,我这里只是做了下简单的封装,并且可能也封装的不好,大家根据自己的业务,到时候会有更好的封装,方便使用:

package Dao;

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

public class BaseDao {

	// 三大对象
	Connection con = null; // 连接对象
	PreparedStatement ps = null; // sql语句编译对象
	ResultSet rs = null; // 返回结果集,查询对象

	public int executeUpdate(String sql, Object... param) {
		int result = 0;
		try {
			// 通过DBCP获取连接
			con = DbcpUtil.getConnectio();

			ps = con.prepareStatement(sql);
			for (int i = 0; i < param.length; i++) {
				ps.setObject(i+1, param[i]);
			}
			result = ps.executeUpdate();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			DbcpUtil.closeConnection();
		}
		return result;
	}

	public ResultSet executeQuery(String sql, Object... param) {
		try {
			con = DbcpUtil.getConnectio();
			ps = con.prepareStatement(sql);
			if (param != null) {
				for (int i = 0; i < param.length; i++) {
					ps.setObject(i++, param[i]);
				}
			}
			rs = ps.executeQuery();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return rs;
	}

}

测试

package Dao;

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

public class Test01Dao extends BaseDao {

	// 修改一个good的名字
	public int updateTest(String sql, String goodName, int goodId) {
		return this.executeUpdate(sql, goodName, goodId);
	}

	// 查询all
	public void queryTest(String sql) {
		this.executeQuery(sql);
		try {
			while (rs.next()) {
				System.out.println(rs.getInt(1)); // 从第一列返回
				System.out.println(rs.getString(2)); // 从第二列返回
				System.out.println(rs.getInt(3)); // 从第三列返回
				System.out.println(rs.getInt(4)); // 从第四列返回
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			DbcpUtil.closeConnection();
		}
	}

	public static void main(String[] args) {
		Test01Dao test01Dao = new Test01Dao();
		// test01Dao.queryTest("select * from good");
		int res = test01Dao.updateTest("update good set goodname=? where goodid=?", "hello", 17);
		if (res == 1) {
			System.out.println("修改成功");
		}

	}

}

查询全部结果,测试成功:

在这里插入图片描述

执行修改,这里只是执行了修改,删除和增加还用演示吗,不用了吧:

结果,测试成功:

在这里插入图片描述

小结

那看到这里我们发现这些都不是很难,反而很简单有没有,而且特别方便,在面对实际业务开发的时候在这层代码上进行封装和继承,可以更大的简化我们的代码开发;
那看到这里了,是不是可以关注下博主,希望这篇文章对你有帮助,后面还会有很多的,同时也谢谢大家观看
下期预告:mvc、servlet;

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值