jdbc编程的步骤大致分为:
1.加载数据库驱动,首先对于不同的数据库要导入其相应的jar包,我这里是mysql数据库,可直接在eclipse中建立maven项目,在maven中导入其对应的jar包
以下为加载jdbc驱动
Class.forName("com.mysql.jdbc.Driver");
2.通过DriverManager获取数据库连接
其中第一个参数为mysql地址和其对应的端口(当然如果有服务器也可以使用服务器的公网ip和mysql的端口),第二个参数和第三个参数为mysql的用户名和密码
Connection conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/class",
"root","123456"
);
3.通过Statement对象执行sql语句,可通过Connection创建Statement对象
Statement stmt = conn.createStatement();
学过mysql的都知道sql语句分为
1、数据操纵语言(DML):用来操纵数据库中数据的命令。包括:select、insert、update、delete。 2、数据定义语言(DDL):用来建立数据库、数据库对象和定义列的命令。包括:create、alter、drop。 3、数据控制语言(DCL):用来控制数据库组件4.数据库查询语言(DQL):用来查询数据库
其中对于DML语言
执行DML时使用executeUpdate(sql)返回受影响的行数
执行DQL时使用executeQuery(sql)返回一个ResultSet对象,ResultSet中的next()方法使结果集的指针指向下一行,ResultSet结果集的指针默认指向第一行
ResultSet s = stmt.executeQuery("select languages.*"+"from languages"
);
while(s.next()) {
System.out.println(s.getInt(1)+"\t"+s.getString(2));
}
方法getInt(1)表示获取第一列的数据,当然你如果知道列名也可以用列名做参数
执行DDL时使用 使用execute 返回类型为Boolean类型 表示执行该sql后是否返回ResultSet结果集 如果有 可以调getResultSet来返回ResultSet对象,getUpdateCount返回受影响的行数
使用PreparedStatement执行sql语句,在执行sql语句时,数据库都会根据sql语句来创建新的执行计划,如果反复执行类似的sql语句,必定会降低数据库的执行效率,所以使用预编译的sql语句可大大提高数据库效率,同时PreparedStatement还可有效的防止sql注入
PreparedStatement pstm = conn.prepareStatement("insert into jdbc_test values(null,?,1);");
pstm.setString(1, "ruby");
pstm.executeUpdate();
使用ResultSetMeteData分析结果集
//得到RsesultSetMetaData对象
ResultSetMetaData rd = rs.getMetaData();
//获取列的数量
int col_number = rd.getColumnCount();
System.out.println("列的数量为"+col_number);
//获取指定索引的列名与列的类型
for(int i = 1;i < col_number;i++) {
System.out.println("索引"+i+"的列名:"+rd.getColumnName(i)+"类型:"+rd.getColumnTypeName(i));
}
使用数据库池管理连接:
数据库每次创建连接都会消耗一定的时间,使用数据库连接池的好处就是当用户不使用连接是,把连接保存起来,给下一个用户使用,从而提高数据库使用效率
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(user);
ds.setPassword(pass);
ds.setInitialSize(2);
ds.setMaxActive(100);
//使用连接池中的数据库连接
Connection conn = ds.getConnection();
String sql = "select * from languages";
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
封装
为了使用jdbc的效率,不能每次都写加载数据等一些重复的工作
所以我们可以写一个工具类,提供一些方法来获取和关闭连接
我这里以数据库连接池为例
import org.apache.commons.dbcp.BasicDataSource;
/**
* 使用连接池技术管理数据库连接
*
* @author Administrator
*
*/
public class DButil2 {
// 数据库连接池
private static BasicDataSource ds;
// 为不同线程管理连接
private static ThreadLocal<Connection> tl;
static {
try {
Properties prop = new Properties();
// InputStream is =
// DButil2.class.getClassLoader().getResourceAsStream("day01/config.properties");
FileInputStream is = new FileInputStream("C:\\Users\\Administrator\\Desktop\\mysql.ini");
prop.load(is);
is.close();
System.out.println("k");
// 初始化连接池
ds = new BasicDataSource();
// 设置驱动 (Class.forName())
ds.setDriverClassName(prop.getProperty("driver"));
// 设置url
ds.setUrl(prop.getProperty("url"));
// 设置数据库用户名
ds.setUsername(prop.getProperty("user"));
// 设置数据库密码
ds.setPassword(prop.getProperty("pwd"));
// 初始连接数量
ds.setInitialSize(Integer.parseInt(prop.getProperty("initsize")));
// 连接池允许的最大连接数
ds.setMaxActive(Integer.parseInt(prop.getProperty("maxactive")));
// 设置最大等待时间
// ds.setMaxWait(Integer.parseInt(prop.getProperty("maxwait")));
// // 设置最小空闲数
// ds.setMinIdle(Integer.parseInt(prop.getProperty("minidle")));
// // 设置最大空闲数
// ds.setMaxIdle(Integer.parseInt(prop.getProperty("maxidle")));
// // 初始化线程本地
tl = new ThreadLocal<Connection>();
System.out.println("k");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接
*
* @throws SQLException
*/
// String sql = "select * from languages";
public static Connection getConnection() {
/*
* 通过连接池获取一个空闲连接
*/
try {
Connection conn = ds.getConnection();
return conn;
}
catch (Exception e) {
//System.out.println("j");
e.printStackTrace();
throw new RuntimeException(e);
}
// tl.set(conn);
}
/**
* 关闭数据库连接
*/
public static void closeConnection(Connection conn) {
try {
if (conn != null) {
/*
* 通过连接池获取的Connection 的close()方法实际上并没有将 连接关闭,而是将该链接归还。
*/
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
数据库事物
我们知道数据库的修改表上的数据时是自动提交 保存 如果表上的数据被改动,没有经过提交保存就再次改就会抛出异常 以下是一个例子
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
import day01.DBUtil2;
/**
* 与用户相关的业务逻辑
*
* @author Administrator
*
*/
public class UserService {
public static void main(String[] args) {
/*
* 程序启动后: 选择1,2,3,4等操作 1:注册新用户 用户ID从1开始 2:更改用户信息 3:删除用户信息 4:查询用户信息
*/
System.out.println("请输入选项:");
System.out.print("1:注册 ");
System.out.print("2:登录 ");
System.out.print("3:修改 ");
System.out.print("4:删除 ");
System.out.println("5:查询 ");
System.out.println("6:转账 ");
Scanner scanner = new Scanner(System.in);
int option = Integer.parseInt(scanner.nextLine().trim());
switch (option) {
case 1:
// 注册
regUser(scanner);
break;
case 2:
// 登录
login(scanner);
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
giveMoney(scanner);
break;
}
}
/**
* 转账操作
*
* @param scanner
*/
public static void giveMoney(Scanner scanner) {
/*
* 1:获取用户输入的信息 2:必要的验证,看看转出账户余额是否够 --事务开始的地方 3:更新转出账户的余额 4:更新转入账户的余额 --提交事务的地方
*/
System.out.println("现在是转账操作");
System.out.println("请输入您的账号");
String fromUser = scanner.nextLine().trim();
System.out.println("请输入收款人的账号");
String toUser = scanner.nextLine().trim();
System.out.println("请输入转出金额");
String money = scanner.nextLine().trim();
// 2
String countSql = "SELECT money " + "FROM user_fanchuanqi " + "WHERE name='" + fromUser + "'";
try {
Connection conn = DBUtil2.getConnection();
// 关闭自动提交事务
conn.setAutoCommit(false);
Statement state = conn.createStatement();
ResultSet rs = state.executeQuery(countSql);
// 判断是否查询出数据
if (rs.next()) {
int count = rs.getInt(1);
// 判断余额是否足够
if (count >= Integer.parseInt(money)) {
// 执行转账操作
// 开始纳入事务控制,因为开始执行DML操作了
String fromSql = "UPDATE user_fanchuanqi " + "SET money=money-" + money + " " + "WHERE name='"
+ fromUser + "'";
// 修改当前用户的余额
if (state.executeUpdate(fromSql) > 0) {
// 修改收款人的余额
String toSql = "UPDATE user_fanchuanqi " + "SET money=money+" + money + " " + "WHERE name='"
+ toUser + "'";
if (state.executeUpdate(toSql) > 0) {
System.out.println("转账成功");
/*
* 两次更新账户操作均成功,我们才 认为这次转账操作完毕。提交事务
*/
conn.commit();
} else {
System.out.println("转账失败:没有收款人" + toUser);
/*
* 若第二次更新操作失败,那么整次 操作就算作失败。应该回滚事务。
*/
conn.rollback();
}
}
} else {
System.out.println("余额不足");
}
} else {
System.out.println("没有该用户:" + fromUser);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil2.closeConnection();
}
}
/**
* 登录操作
*
* @param scanner
*/
public static void login(Scanner scanner) {
/*
* 1:要求用输入用户名及密码 2:根据用户输入作为条件去表中查询 3:若查询出数据,说明输入正确
*/
System.out.println("现在是登录操作");
System.out.println("请输入用户名:");
String user = scanner.nextLine().trim();
System.out.println("请输入密码:");
String pwd = scanner.nextLine().trim();
try {
Connection conn = DBUtil2.getConnection();
String sql = "SELECT * FROM user_fanchuanqi " + "WHERE name=? AND password=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, user);
ps.setString(2, pwd);
ResultSet rs = ps.executeQuery();
// 根据用户输入的能否查到数据
if (rs.next()) {
System.out.println("登录成功!");
} else {
System.out.println("用户名或密码错误!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil2.closeConnection();
}
}
/**
* 注册操作
*
* @param scanner
*/
public static void regUser(Scanner scanner) {
/*
* 若是注册操作: 1:获取用户输入的相关信息 2:获取连接 3:获取Statement 4:先获取id的最大值 5:对该值+1,作为当前记录的主键值
* 6:插入记录 7:关闭连接
*/
try {
// 1
System.out.println("现在是注册操作:");
System.out.println("请输入用户名:");
String user = scanner.nextLine().trim();
System.out.println("请输入密码:");
String pwd = scanner.nextLine().trim();
System.out.println("请输入账户金额:");
String money = scanner.nextLine().trim();
System.out.println("请输入邮箱:");
String email = scanner.nextLine().trim();
// 2
Connection conn = DBUtil2.getConnection();
// 3
Statement state = conn.createStatement();
// 4
String idSql = "SELECT MAX(id) id FROM user_fanchuanqi";
// 5
ResultSet rs = state.executeQuery(idSql);
int id = -1;
if (rs.next()) {
id = rs.getInt("id");
}
// 统计出最大值后,对ID加1
id++;
rs.close();
// 6
/*
* INSERT INTO user_fanchuanqi VALUES(1,'jack','1234',5000,'[email protected]')
*
*/
String sql = "INSERT INTO user_fanchuanqi " + "VALUES" + "(" + id + "," + "'" + user + "'," + "'" + pwd
+ "'," + "" + money + "," + "'" + email + "'" + ")";
System.out.println(sql);
if (state.executeUpdate(sql) > 0) {
System.out.println("注册成功!欢迎你:" + user);
} else {
System.out.println("呵呵");
}
DBUtil2.closeConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
}
批量更新数据
/**
* 使用批处理批量更新数据
* @author Administrator
*
*/
public class BatchDemo {
public static void main(String[] args){
try{
Connection conn
= DBUtil2.getConnection();
Statement state
= conn.createStatement();
for(int i=1000;i<20000;i++){
String sql
="INSERT INTO user_fanchuanqi " +
"(id,name) " +
"VALUES" +
"("+i+",'test"+i+"')";
// state.executeUpdate(sql);
//缓存,等待一起执行
state.addBatch(sql);
if(i%500==0){
state.executeBatch();
state.clearBatch();
}
}
state.executeBatch();
}catch(Exception e){
e.printStackTrace();
}finally{
DBUtil2.closeConnection();
}
}