JDBC
1. 概念
JDBC(Java DataBase Connectivity(Java数据库的连接))是一种用于执行SQL语句的Java API,可以为多种关系数据库(oracle,mysql,SQL server)提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序.
2.使用JDBC的步骤
我们不管使用哪一种数据库,都需要去导入这个数据库给我们提供的jdbc实现的jar包;
2.1 注册驱动
方法一(这种驱动注册方式很少使用)
//通过系统的属性设置注册驱动
System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver");
//注册多个驱动,则中间用:隔开System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver:com.oracle.jdbc.Driver");
这种驱动注册方式很少使用
方法二(使用最多的一种注册驱动方式)
//Class类的forName方法中对参数指定的类进行了装载操作
Class.forName("com.mysql.jdbc.Driver");
方法三(不推荐)
//会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖。
DriverManager.registerDriver(newcom.mysql.jdbc.Driver());
2.2 拿到连接
//2.建立连接 ip 端口号 账号 密码 如果连接的是本地数据库 端口号为3306 此时可以省略不写
Connection conn= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jdbcdemo", "root", "123456");
2.3 获得语句对象(Statement)
//3获取语句对象
Statement statement = conn.createStatement();
//建表语句
String sql="create table student(id bigint(10),name varchar(255),age int(10))";
2.4 执行语句
//4.执行语句
statement.execute(sql);
2.5 关闭资源
//5.释放资源
statement.close();
conn.close();
3. CRUD
3.1 添加
public void add() {
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.建立连接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "123456");
//3.获取语句对象
Statement statement = conn.createStatement();
//准备sql语句
String sql ="insert into student (id,name,age) values (1,'小王',18)";
//4.执行语句
statement.execute(sql);
} catch (Exception e) {
e.printStackTrace();
}finally{
if(set!=null)
set.close();
if(statement!=null)
statement.close();
if(conn!=null)
conn.close();
}
}
3.2 修改
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.建立连接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "123456");
//3.获取语句对象
Statement statement = conn.createStatement();
String sql ="update student set name='老王'";
//返回的数值代表的是受影响的行数
int i = statement.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
}finally{
if(set!=null)
set.close();
if(statement!=null)
statement.close();
if(conn!=null)
conn.close();
}
3.3 删除
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.建立连接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "123456");
//3.获取语句对象
Statement statement = conn.createStatement();
String sql="delete from student where id = 1";
statement.execute(sql);
} catch (Exception e) {
e.printStackTrace();
}finally{
if(set!=null)
set.close();
if(statement!=null)
statement.close();
if(conn!=null)
conn.close();
}
3.4 查找
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.建立连接
Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "123456");
//3.获取语句对象
Statement statement = conn.createStatement();
String sql="select * from student where id =2 ";
ResultSet set = statement.executeQuery(sql);
while(set.next()){
System.out.print(set.getLong("id"));
System.out.print(set.getString("name"));
System.out.print(set.getInt("age"));
System.out.print(" ");
} catch (Exception e) {
e.printStackTrace();
}finally{
if(set!=null)
set.close();
if(statement!=null)
statement.close();
if(conn!=null)
conn.close();
}
3.5 抽取出来的工具类
public class JDBCUtil {
private JDBCUtil(){}
static private JDBCUtil instance=null;
static private Properties properties=new Properties();
//静态代码块,优先加载
static{
try {
//加载properties文件(Thread.currentThread()获取当前线程,getContextClassLoader()获取类加载器,getResourceAsStream() 获取流资源)
//properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
//通过字节码对象来获取流资源
//properties.load(JDBCUtil.class.getResourceAsStream("/db.properties"));
//通过字节码对象获取类加载器,在获取流资源
properties.load(JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties"));
instance=new JDBCUtil();
Class.forName(properties.getProperty("DriverClassName"));
} catch (Exception e) {
e.printStackTrace();
}
}
//单例
public static JDBCUtil getInstance(){
return instance;
}
//获取连接
public Connection getConnection(){
Connection connection=null;
try {
connection = DriverManager.getConnection(properties.getProperty("url"),properties.getProperty("username"), properties.getProperty("password"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return connection;
}
//关闭全部资源
public void close(ResultSet rs,Statement st,Connection connection){
try {
if(rs!=null){
rs.close();
}
} catch (Exception e) {
// TODO: handle exception
}finally{
try {
if(st!=null)
st.close();
} catch (Exception e2) {
// TODO: handle exception
}finally{
try {
if (connection!=null) {
connection.close();
}
} catch (Exception e3) {
// TODO: handle exception
}
}
}
}
}
properties文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/jdbcdemo
username=root
password=123456
4.PreparedStatement
4.1 概念
预编译语句PreparedStatement 是java.sql中的一个接口,它是Statement的子接口。通过Statement对象执行SQL语句时,需要将SQL语句发送给DBMS,由 DBMS首先进行编译后再执行。预编译语句和Statement不同,在创建PreparedStatement 对象时就指定了SQL语句,该语句立即发送给DBMS进行编译。当该编译语句被执行时,DBMS直接运行编译后的SQL语句,而不需要像其他SQL语句那样首先将其编译,在执行。
4.2 作用
- 思路清楚,使用方便:不需要我们去拼接字符串,特别是字段很多的时候
- 速度,效率更高,更快
- 防SQL注入: String name = " ’ or 1=1 or ’ "
4.3 使用
添加
public void add(Student u) {
//获取连接
Connection connection = JDBCUtil.getInstance().getConnection();
//准备sql语句
String sql="INSERT INTO student (username,password,age,sex,intro) VALUES(?,?,?,?,?)";
try {
//获得PreparedStatement对象
PreparedStatement statement = connection.prepareStatement(sql);
//设置sql语句里的值
statement.setString(1,u.getUsername());
statement.setString(2,u.getPassword());
statement.setInt(3, u.getAge());
statement.setBoolean(4, u.getSex());
statement.setString(5, u.getIntro());
//执行sql
statement.execute();
//关闭流
JDBCUtil.getInstance().close(null, statement, connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
删除
public void delete(long id) {
//获取连接
Connection connection = JDBCUtil.getInstance().getConnection();
//准备sql
String sql="DELETE FROM student where id=?";
try {
//获取PreparedStatement对象
PreparedStatement statement = connection.prepareStatement(sql);
//设置sql里的值
statement.setLong(1, id);
//执行sql
statement.execute();
//关闭流
JDBCUtil.getInstance().close(null, statement, connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
修改
public void update(Student u) {
//获取连接
Connection connection = JDBCUtil.getInstance().getConnection();
//准备sql
String sql="UPDATE student set username=?,password=? ,age=? ,sex=? ,intro=? WHERE id=?";
try {
//创建PreparedStatement对象
PreparedStatement statement = connection.prepareStatement(sql);
//设置sql里的值
statement.setString(1,u.getUsername());
statement.setString(2,u.getPassword());
statement.setInt(3, u.getAge());
statement.setBoolean(4, u.getSex());
statement.setString(5, u.getIntro());
statement.setLong(6, u.getId());
//执行sql
statement.executeUpdate();
//关闭流资源
JDBCUtil.getInstance().close(null, statement, connection);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
查询
public Student query(Student u) {
//声明一个student对象
Student stu=null;
//获取连接
Connection connection = JDBCUtil.getInstance().getConnection();
//准备sql
String sql="SELECT id,username,password,age,sex,intro from student where username=? and password=? and age=? and sex=? and intro=?";
try {
//创建PreparedStatement对象
PreparedStatement statement = connection.prepareStatement(sql);
//设置sql里的值
statement.setString(1,u.getUsername());
statement.setString(2,u.getPassword());
statement.setInt(3, u.getAge());
statement.setBoolean(4, u.getSex());
statement.setString(5, u.getIntro());
//执行sql,返回一个结果集
ResultSet resultSet = statement.executeQuery();
//遍历
while(resultSet.next()){
//new一个student对象
stu=new Student();
//封装成一个student对象
stu.setId(resultSet.getInt("id"));
stu.setPassword(resultSet.getString("password"));
stu.setUsername(resultSet.getString("username"));
stu.setAge(resultSet.getInt("age"));
stu.setSex(resultSet.getBoolean("sex"));
stu.setIntro(resultSet.getString("intro"));
}
//关闭流资源
JDBCUtil.getInstance().close(resultSet, statement, connection);
} catch (SQLException e) {
e.printStackTrace();
}
return stu;
}
4.4 拿到主键
connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
public void add(Account account) {
Connection connection = JDBCUtil2.getInstance().getConnection();
try {
//向数据库添加一条数据并拿到该数据的主键
PreparedStatement statement = connection.prepareStatement("insert into account (name,money) values(?,?)",Statement.RETURN_GENERATED_KEYS);
statement.setString(1, account.getName());
statement.setDouble(2, account.getMoney());
statement.execute();
ResultSet resultSet = statement.getGeneratedKeys();
while(resultSet.next()){
System.out.println(resultSet.getLong(1));
}
JDBCUtil2.getInstance().close(resultSet, statement, connection);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
5. 事务
5.1 概念
事务: 程序里面的一组操作,要不都成功,要不都失败
5.2 示例
5.3 认识
事务的ACID属性:
- Atomic原子性、Consistency一致性、Isolation隔离性和Durability持久性。
- 原子性:指整个事务是不可以分割的工作单元。只有事务中所有的操作执行成功,才算整个事务成功,事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该回到执行事务前的状态。
- 一致性:指数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。例如对于银行转账事务,不管事务成功还是失败,应该保证事务结束后两个转账账户的存款总额是与转账前一致的。
- 隔离性:指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。(Hibernate在讲) JPA 框架
- 持久性:指的是只要事务成功结束它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
5.4 总结
-
事务:是用户定义的一组操作。这组操作要么都做(都成功),要么都不做;
-
事务处理:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),要么整个事务回滚(rollback)到最初状态
-
处理事务的两个动作:
-
提交:commit: 当整个事务中,所有的逻辑单元都正常执行成功. ---->提交事务.—数据已经提交,不能更改.
-
回滚:rollback: 当整个事务中,有一个逻辑单元执行失败, ---->回滚事务.撤销该事务中的所有操作—>恢复到最初的状态
-
6. 连接池
最开始的时候就创建一些连接对象放到连接池中 请求来了可以直接在连接池中获取连接 操作数据库,操作完成以后 释放连接 回到连接池 等待下一次被请求使用 ,初始的时候 创建了一些连接 最小连接数 ,请求并发的时候,创建更多的连接 最大连接
6.1 常见连接池
dbcp(spring集成) c3p0(Hibernate框架已经集成C3P0) druid(常用)
6.2 DBCP连接实现
public class JDBCUtil2 {
private JDBCUtil2(){}
static private JDBCUtil2 instance=null;
static private Properties properties=new Properties();
static private DataSource dataSource;
//静态代码块,优先加载
static{
try { properties.load(JDBCUtil2.class.getClassLoader().getResourceAsStream("db.properties"));
instance=new JDBCUtil2();
//创建dataSource对象
dataSource=BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static JDBCUtil2 getInstance(){
return instance;
}
//获取连接
public Connection getConnection(){
try {
//拿到连接对象
return dataSource.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}