JDBC
Java Database Connectivity :java访问数据库的解决方案。
JDBC定义一套标准接口,即访问数据库的通用API,不同的数据库厂商根据各自数据库的特点去实现这些接口。这样程序员使用不同的数据库使用同一套api即可,只需要加载不同驱动。
JDBC接口
- DriverManager驱动管理
- Connection 连接接口
- DatabaseMetaData 数据库元数据接口,有获取驱动版本、厂商名称等各种数据库信息的方法
- Statement语句对象接口
- PreparedStatement 预编译语句对象接口
- ResultSet 结果集接口
- ResultSetMetaData 表的元数据接口,获取表的各种信息
JDBC工作过程:
-
加载驱动,建立连接
-
创建语句对象
-
执行SQL语句
-
处理结果集
-
关闭连接
-
建立一个提供数据库接口的类
public class DBUtils {
public static Connection getConn() throws Exception{
Properties prop = new Properties();
InputStream ips = DBUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//jdbc.properties是配置文件
prop.load(ips);
String username = prop.getProperty("username");
String password = prop.getProperty("password");
String driver = prop.getProperty("driver");
String url = prop.getProperty("url");
//注册驱动
//Class.forName("com.mysql.jdbc.Driver");动态加载类,驱动类通过static块实现在DriverManager中自动注册
Class.forName(driver);
//获取连接对象
//Connection只是接口,真正的实现是数据库厂家的驱动类包中完成的
//根据url找到与之匹配的Driver对象,调用其方法获得连接
Connection conn = DriverManager.getConnection(url,username,password);
return conn;
}
}
- 配置文件里的内容:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/newdb3?useUnicode=true&characterEncoding=UTF-8
username=root
password=
数据库连接池DBCP
- DataBaseConnectivityPool
- 使用连接池写一个获取连接的类:
public class Demo01 {
public static void main(String[] args) throws IOException, SQLException {
//chuangjian数据源对象
BasicDataSource ds = new BasicDataSource();//连接池对象
//读取配置文件
Properties p = new Properties();
InputStream ips = Demo01.class.getClassLoader().getResourceAsStream("jdbc.properties");
p.load(ips);
String driver = p.getProperty("driver");
String url = p.getProperty("url");
String username = p.getProperty("username");
String password = p.getProperty("password");
//设置连接信息
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
ds.setInitialSize(3);//设置初始连接信息
ds.setMaxActive(5);//设置最大连接数量
//获取连接对象
Connection conn = ds.getConnection();
System.out.println(conn);
}
}
PreparedStatement
- 预编译的SQL执行对象
- 好处:
- 可以避免字符串的拼接,使代码结构更为简洁,不易出错
- 可以避免SQL注入风险(因为在编译时已经把SQL逻辑锁死,不会被用户输入的内容改变逻辑)
- 如果SQL语句中有变量则使用PreparedStatement 如果没有变量则使用Statement
try (
Connection conn = DBUtils.getConn();
){
/*Statement stat = conn.createStatement();
String sql = "insert into jdbcuser values(null,'"+name+"','"+password+"')";
stat.executeUpdate(sql);*/
String sql = "insert into jdbcuser values(null,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, name);
ps.setString(2, password);
ps.executeUpdate();
System.out.println("注册成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
批量操作
try (
Connection conn = DBUtils.getConn();
){
String sql = "insert into jdbcuser(username) values(?)";
PreparedStatement ps = conn.prepareStatement(sql);
for(int i=1;i<=100;i++) {
ps.setString(1, "name"+i);
ps.addBatch();//添加到批量列表
//避免批量列表数据过多,导致内存溢出
if(i%20==0) {
ps.executeBatch();
}
}
ps.executeBatch();//批量执行
System.out.println("over");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
事务相关
create table jdbcaccount(id int,name varchar(10),money int);
insert into jdbcaccount values(1,‘Tom’,5000),(2,‘Jerry’,10);
- 打开或关闭自动提交
conn.setAutoCommit(true/false); - 提交
conn.commit(); - 回滚
conn.rollback();
try (
Connection conn = DBUtils.getConn();
){
conn.setAutoCommit(false);//关掉自动提交,即开启事务
Statement stat = conn.createStatement();
String sql1 = "update jdbcaccount set money = money-2000 where name = 'Tom'";
String sql2 = "update jdbcaccount set money = money+2000 where id=2";
stat.executeUpdate(sql1);
stat.executeUpdate(sql2);
//查询tom的钱是否大于0
String sql3 = "select money from jdbcaccount where id =1";
ResultSet rs = stat.executeQuery(sql3);
while(rs.next()) {
int m = rs.getInt(1);
if(m>=0) {
conn.commit();
System.out.println("success");
}else {
conn.rollback();
System.out.println("failed");
}
}
//连接是从连接池里拿到的,所以要设置回原来的样子,否则影响下次使用
conn.setAutoCommit(true);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
获取自增主键的值
try (Connection conn = DBUtils.getConn();) {
Statement stat = conn.createStatement();
String sql = "insert into jdbcuser values(null,'lucy','asd')";
//获取自增主键
stat.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stat.getGeneratedKeys();
rs.next();
int id = rs.getInt(1);
System.out.println(id);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
元数据
-
数据库元数据
-
表元数据
DatabaseMetaData dbmd = conn.getMetaData();
System.out.println("数据库厂商名称: "+dbmd.getDatabaseProductName());
System.out.println("数据库驱动版本: "+dbmd.getDriverMajorVersion());
System.out.println("数据库链接地址: "+dbmd.getURL());
System.out.println("数据库用户名: "+dbmd.getUserName());
Statement stat = conn.createStatement();
String sql = "select * from emp";
ResultSet rs = stat.executeQuery(sql);
//获取表的元数据
ResultSetMetaData rsmd = rs.getMetaData();
//字段数量
int count = rsmd.getColumnCount();
for(int i=0;i<count;i++) {
//字段名
String name = rsmd.getColumnName(i+1);
//字段类型
String type = rsmd.getColumnTypeName(i+1);
System.out.println(name+":"+type);
}