JDBC: Java连接MySQL

一、Java连接MySQL数据库步骤

1.加载驱动
新建一个动态网页项目后,首先在WebContent目录下WEB-INF下的lib文件夹添加mysql-connector-java-5.1.19-bin.jar,然后右键项目名称,构建配置路径,选择库,选择刚刚添加的jar包

Class.forName("com.mysql.jdbc.Driver");

2.打开连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库表","root","password");

3.执行查询

stmt = (Statement) con.createStatement();
//运行结果返回一个ResultSet对象
rst = stmt.executeQuery("select * from wp_users");

或者

String sql = "select * from wp_users";

4.处理结果

while(rst.next()){
	System.out.println(rst.getString(1)+"\t"+rst.getString(2)+"\t"+rst.getString(3)+"\t"+rst.getString(4)+"\t"+rst.getString(5)+"\t"+rst.getString(6)+"\t"+rst.getString(7));
}

5.清理环境

public static void closeAll(Connection conn, Statement stmt, ResultSet rs) {
	try {
		if (rs != null)
			rs.close();
		if (stmt != null)
			stmt.close();
		if (conn != null)
			conn.close();
	} catch (SQLException e) {
		// TODO: handle exception
		e.printStackTrace();
	}
}

二、JDBC基本操作:CRUD

2.1 Statement

Statement最为重要的方法是:

  • int executeUpdate (String sql):执行更新操作,即执行insert、update、delete语句,其实这个方法也可以执行create table、alter table,以及drop table等语句,但我们很少会使用JDBC来执行这些语句;
  • ResultSet executeQuery (String sql):执行查询操作,执行查询操作会返回ResultSet,即结果集。

2.2 ResultSet 之滚动结果集(了解)

ResultSet表示结果集,它是一个二维的表格!ResultSet内部维护一个行光标(游标),ResultSet提供了一系列的方法来移动游标:
下一行:默认只能使用它,其他的方法存在,但不能使用!默认的结果集不可滚动!上一行,下N行,上N行,到N行!

前面的查询都是预先知道列的名字, 例如name,然后通过rs.getString(“name”)来获取当前行中name列的内容, 实际上JSBC可以直接获取result set对象的列名.根据取到的表的列名, 可以动态的显示查询的各列内容, result对象的列名可由ResultSet MetaData元数据获得, ResultSet MetaData可以返回原数据,遍历原数据 即可获知ResultSet 中哪些列, 每一列是什么类型.
获取结果集元数据
 得到元数据:rs.getMetaData(),返回值为ResultSetMetaData;
 获取结果集列数:int getColumnCount()
 获取指定列的列名:String getColumnName(int colIndex)

结果集特性
当使用Connection的createStatement时,已经确定了Statement生成的结果集是什么特性。
 是否可滚动
 是否敏感
 是否可更新

con.createSttenextment()//生成的结果集:不滚动、不敏感、不可更新!

con.createStatement(int,int)//具体看下面解释

Statement默认返回的Result是只可以往后滚动的,因此只有next(),last()方法是可用的,要想使用previous(),first()方法,可以通过这么定义Statement:

stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,CONCUR_UPDATABLE);
stmt.executeQuery("...");

参数解释:
 ResultSet.TYPE_FORWARD_ONLY:不滚动结果集;
 ResultSet.TYPE_SCROLL_INSENSITIVE:滚动结果集,但结果集数据不会再跟随数据库而变化;
 ResultSet.TYPE_SCROLL_SENSITIVE :滚动结果集,但结果集数据不会再跟随数据库而变化;
第二个参数:
 CONCUR_READ_ONLY:结果集是只读的,不能通过修改结果集而反向影响数据库;
 CONCUR_UPDATABLE:结果集是可更新的,对结果集的更新可以反向影响数据库。

2.3 示例: 查询用户

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mysql.jdbc.Statement;

public class Conn {
	Connection conn = null;
	Statement stmt = null;
	ResultSet rst = null;
	Connection con;

	public Connection getConnection() throws ClassNotFoundException, SQLException {
		try {
			Class.forName("com.mysql.jdbc.Driver");
			System.out.println("数据库驱动加载成功");

			con = DriverManager.getConnection("jdbc:mysql://localhost/shopping", "root", "password");
			System.out.println("数据库连接成功");

			stmt = (Statement) con.createStatement();
			rst = stmt.executeQuery("select * from users");
			while (rst.next()) {
				System.out.println(rst.getString(1) + "\t" + rst.getString(2) + "\t" + rst.getString(3) + "\t"
						+ rst.getString(4) + "\t" + rst.getString(5));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (rst != null)
				rst.close();
			if (stmt != null)
				stmt.close();
			if (conn != null)
				conn.close();
		}
		return con;
	}

	public static void main(String[] args) throws ClassNotFoundException, SQLException {
		Conn c = new Conn();
		c.getConnection();
	}
}

利用手动实现DbUtils进行改进, 将连接操作封装到 jdbcutils.java , 调用方法:

Connection con = JdbcUtils.getConnection();

package jdbcutils;

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

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

public class JdbcUtils {
	private static final String dbconfig = "dbconfig.properties";
	private static Properties prop = new Properties();
	static {
		try {
			InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(dbconfig);
			prop.load(in);
			Class.forName(prop.getProperty("driverClassName"));
		} catch (IOException e) {
			throw new RuntimeException(e);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static Connection getConnection() {
		try {
			return DriverManager.getConnection(prop.getProperty("url"), prop.getProperty("username"),
					prop.getProperty("password"));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}

2.4 DBUtils简介

DBUtils是Apache Commons组件中的一员,开源免费!
DBUtils是对JDBC的简单封装,但是它还是被很多公司使用!
DBUtils的Jar包:dbutils.jar

DBUtils主要类

  • DbUtils:都是静态方法,一系列的close()方法;
  • QueryRunner:
    • update():执行insert、update、delete;
    • query():执行select语句;
    • batch():执行批处理。

使用JDBC的基本用法和操作来与数据库交互,由于每操作一次数据库,都会执行一次创建和断开Connection对象的操作,这种频繁的操作Connection对象十分影响数据库的访问效率,并且增加了代码量,所以在实际开发中,开发人员通常会使用数据库连接池来解决这些问题。Apache组织还提供了一个DBUtils工具类库,该类库实现了对JDBC的简单封装,能在不影响性能的情况下极大地简化JDBC的编码工作。

三、PreparedStatement

PreparedStatement与Statement的最大区别是PreparedStatement可以使用参数, 也就是?号. PreparedStatement允许使用不完整的SQL语句,空缺的部分使用问号代替 ,直到执行前的时候设置进去.

PreparedStatement叫预编译声明,PreparedStatement是Statement的子接口,你可以使用PreparedStatement来替换Statement。

1. PreparedStatement的好处:

  • 防止SQL攻击;
  • 提高代码的可读性,以可维护性;
  • 提高效率 。

防止SQL攻击的几种方法:

  • 过滤用户输入的数据中是否包含非法字符;
  • 分步交验!先使用用户名来查询用户,如果查找到了,再比较密码;
  • 使用PreparedStatement。

2. PreparedStatement预处理的原理:

  • 前提:连接的数据库必须支持预处理!几乎没有不支持的!
  • 每个pstmt都与一个sql模板绑定在一起,先把sql模板给数据库,数据库先进行校验,再进行编译。执行时只是把参数传递过去而已!
  • 若二次执行时,就不用再次校验语法,也不用再次编译!直接执行!

3. PreparedStatement批处理
Statement与PreparedStatement都能够批处理SQL语句, 也就是同时执行多条SQL语句, 这些SQL语句必须是insert update delete等SQL语句, 他们执行后都返回一个int类型数,表示影响的行数,Statement与PreparedStatement通过addBatch()方法添加一条SQL语句, 通过executeBatch()方法批量执行SQL语句,返回一个int数组, 代表各句SQL的返回值.

PreparedStatement的批处理有所不同,因为每个PreparedStatement对象都绑定一条SQL模板。所以向PreparedStatement中添加的不是SQL语句,而是给“?”赋值。

con = JdbcUtils.getConnection();
String sql = "insert into stu values(?,?,?,?)";
pstmt = con.prepareStatement(sql);
for(int i = 0; i < 10; i++) {
	pstmt.setString(1, "S_10" + i); //设置第一个参数
	pstmt.setString(2, "stu" + i);
	pstmt.setInt(3, 20 + i);
	pstmt.setString(4, i % 2 == 0 ? "male" : "female");
	
	pstmt.addBatch() ; //将这一组参数保存到集合中
}
pstmt.executeBatch (); //执行批处理

注意: MySQL的批处理需要在连接时将rewriteBatchedStatements设为true才有效.

jdbc:mysql://localhost/shopping?rewriteBatchedStatements=true

四、数据库连接池

1.数据库连接池的概念
使用JDBC的基本用法和操作来与数据库交互,由于每操作一次数据库,都会执行一次创建和断开Connection对象的操作,这种频繁的操作Connection对象十分影响数据库的访问效率,并且增加了代码量,所以在实际开发中,开发人员通常会使用数据库连接池来解决这些问题。

用池来管理Connection,这可以重复使用Connection。有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。池就可以再利用这个Connection对象了。
在这里插入图片描述
知乎 – 数据库连接和C3P0连接池的学习笔记

https://zhuanlan.zhihu.com/p/28831891

2. 使用c3p0

有两种方式,第一种是用代码,第二种是使用配置文件.

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class Conn2 {
	
	public static void fun1() throws PropertyVetoException, SQLException {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://localhost/shopping");
		dataSource.setUser("root");
		dataSource.setPassword("password");
		
		dataSource.setAcquireIncrement(5) ;
		dataSource.setInitialPoolSize(20) ;
		dataSource.setMinPoolSize(2) ;
		dataSource.setMaxPoolSize(50) ;
		
		Connection con = dataSource.getConnection();
		System.out.println(con);
		con.close();
	}
	public static void main(String[] args) throws PropertyVetoException, SQLException {
		fun1();
	}
}

五、DAO与JavaBean

Dao(数据库操作对象database access object)是JDBC下常用的模式,保存数据时, 他将JavaBean的属性拆分成正确的sql语句, 并保存到数据库中, 读取数据时将数据从数据库中取出来, 并通过setter方法设置到JavaBean中, DAO出现之前操作数据库的代码与业务代码都出现在servlet或者JSP中, 不利于业务代码的分离,DAO出现后改变了这一情况, 所有与数据库相关的操作都被拿到了 DAO层实现,servlet或者JSP只操作JavaBean与Dao层, 而Dao层只操作数据库.
在这里插入图片描述
entity文件夹 下有部门类Department.java与员工类Employee.java (JavaBean)
dao文件夹 下有DepartmentDao.java 与 EmployeeDao.java, 包括插入、修改、删除、列出所有数据等.

当我们添加一个Department时,addDepartment.jsp代码如下:

<%
	request.setCharacterEncoding(...);
	String action = request.getParameter("action");
	if("add".equals(action){
		Department department = new Department();
		department.setName(request.getParameter("name"));
		DepartmentDao.insert(department);
	}
%>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值