文章目录
一、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);
}
%>