java JDBC之mysql

一、什么是JDBC  

    JDBC的全称是Java DataBase Connection,也就是Java数据库连接,我们可以用它来操作关系型数据库。

    JDBC接口及相关类在 java.sql 包和 javax.sql 包里。用它来连接数据库,执行操作关系型数据库。

   JDBC接口让Java程序和JDBC驱动实现了松耦合(通过JDBC接口完成的,而驱动只有在通过Class.forName反射机制来加载的时候才会出现),使得切换不同的数据库变得更加简单。

 

二、JDBC的四大物件及其作用

    1)DriverManager 类,负责管理一组数据库驱动
    2)Connection, 由 DriverManager 产生,负责连接指定的数据库
    3)Statement, 由 Connection 对象产生,负责发送sql指令到数据库执行
    4)ResultSet,负责接收查询的结果集

PreparedStatement : 可防止sql 注入
    1)Statement 的一个子接口
    2)适用于循环中使用,或参数有变化的情况
    3)重复的指令只需要编译一次,而普通的 Statement 每次执行都需要编译
    4)给未知?赋值:setXxx( 1,value),setXxx( 2,value) ..

CallableStatement: 调用存过或函数时使用,也是 Statement 的一个子接口。

 

三、JDBC操作数据库的步骤

    1)导入 mysql 架包,bulid path.   java_demo/lib/mysql-connector-java-5.1.46.jar

    2)封装 DbUtil

            加载数据库驱动。   

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

                         oracle:     Class.forName("oracle.jdbc.driver.OracleDriver") ;     

            连接数据库。

               中文处理:

                jdbc:mysql://localhost:3306/test_demo?useUnicode=true&characterEncoding=UTF-8 

                         mysql:      return  DriverManager.getConnection(

                                        "jdbc:mysql://localhost:3306/test_demo","root","123456") ;      

                         oracle:     return DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","scott","tiger") ;  

            关闭数据库连接    

    3)model 包 一个 javabean 

    4) DAO 包

              获取数据库连接

              创建一个Statement。

              执行SQL语句。

              处理结果集。

              关闭数据库连接。

     5) service 操作

 

四、小Demo

model

public class Student {

	private Integer id;
	private String name;
	private String sex;
	private Integer age;

        //省略getter setter

}

DbUtil

import java.sql.*;

//数据库工具类:封装数据库驱动、连接、关闭的方法
public class DbUtil {
	
	public static final String URL = "jdbc:mysql://localhost:3306/test_demo";
	public static final String USER = "root";
	public static final String PASSWORD = "123456";
	
	//1:加载数据库驱动
	static {
		try {
			Class.forName("com.mysql.jdbc.Driver");
			System.out.println("mysql驱动加载成功!");
		} catch (ClassNotFoundException e) {
			System.err.println("mysql驱动加载失败!");
			e.printStackTrace();
		}
	}

	//2. 连接数据库封装成工具类的静态方法
	public static Connection getConn () throws SQLException {
		return DriverManager.getConnection(URL, USER, PASSWORD);
	}
	
	//3.关闭数据库的方法
	public static void close(ResultSet rs,Statement stat,Connection conn){
		try {
			if(rs!=null)
				rs.close();
			if(stat!=null)
				stat.close();
			if(conn!=null)
				conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

DAO

public class StudentDao {

	//增加
	public void addStu(Student stu) {
		Connection conn = null;
		Statement stmt = null;
		String sql = null;
		
		try {
			//不安全,防止sql注入
			sql = "insert into student(name,sex,age) values('" + stu.getName() +"','"+ stu.getSex() +"',"+ stu.getAge() +")";
			//1. 获取数据库连接
			conn = DbUtil.getConn();
			//2. 创建Statment对象
			stmt = conn.createStatement();
			//3. 发送sql指令到数据库服务器执行
			stmt.execute(sql);
			System.out.println("添加成功");
		} catch (SQLException e) {
			System.err.println("添加失败:"+sql);
			e.printStackTrace();
		}finally {
			DbUtil.close(null, stmt, conn);
		}
	}
	//修改
	public void editStu(Student stu) {
		Connection conn = null;
		Statement stmt = null;
		String sql = null;
		
		try {
			//不安全,防止sql注入
			sql = "update student set name='" + stu.getName() +"',age=" + stu.getAge() + " where id=1";
			conn = DbUtil.getConn();
			stmt = conn.createStatement();
			stmt.executeUpdate(sql);
			System.out.println("修改成功");
		} catch (SQLException e) {
			System.err.println("修改失败:"+sql);
			e.printStackTrace();
		} finally {
			DbUtil.close(null, stmt, conn);
		}
	}
	
	//查询所有
	public ArrayList<Student> getList(){
		ArrayList<Student> list = new ArrayList<Student>();
		
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		String sql = null;
		
		try {
			sql = "select * from student";
			conn = DbUtil.getConn();
			stmt = conn.createStatement();
			
			rs = stmt.executeQuery(sql);
			while(rs.next()) {
				//创建Student对象存放记录的值
				Student stu = new Student();
				stu.setId(rs.getInt("id"));
				stu.setName(rs.getString("name")); 
				stu.setSex(rs.getString("sex"));
				stu.setAge(rs.getInt("age"));
				list.add(stu);
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		}  finally {
			DbUtil.close(null, stmt, conn);
		}
		return list;
	}
	
	//删除
	public void deleteStu(String name) {
		Connection conn = null;
		Statement stmt = null;
		String sql = null;
			
		try {
			//不安全,防止sql注入
			sql = "delete from  student where name='" + name +"'";
			conn = DbUtil.getConn();
			stmt = conn.createStatement();
			stmt.executeUpdate(sql);
			System.out.println("删除成功");
		} catch (SQLException e) {
			System.err.println("删除失败:"+sql);
			e.printStackTrace();
		} finally {
			DbUtil.close(null, stmt, conn);
		}
	}
	
}

test

	public static void main(String[] args) {
		StudentDao studentDao = new StudentDao();
		Student stu = new Student("李四","男",18);
		
		//添加
		//studentDao.addStu(stu);
		
		//修改
		stu.setName("张三");
		stu.setAge(17);
		studentDao.editStu(stu);
		
		//查询所有
		ArrayList<Student> list = studentDao.getList();
		for (Student student : list) {
			System.out.println(student);
		}
		
		//删除
		studentDao.deleteStu("张三");
	}


----结果----
mysql驱动加载成功!
修改成功

Student [id=3, name=李四, sex=男, age=18]
Student [id=4, name=张三, sex=男, age=17]

删除成功

DAO 一般使用 PreparedStatement 进行CRUD ,可防止sql注入

//使用 PreparedStatement 进行CRUD 可防止sql注入
	public void addPreStu(Student stu) throws SQLException{		
		Connection conn = null;
		PreparedStatement pstmt = null;		
		String sql = "insert into student(name,sex,age) values(?,?,?)";	//未知值暂时用?代替	
		try {
			conn = DbUtil.getConn();			
			//创建PreparedStatement对象:prepareStatement()
			pstmt = conn.prepareStatement(sql);
			//给?赋值, 从 1 开始
			pstmt.setString(1, stu.getName()); 
			pstmt.setString(2, stu.getSex()); 
			pstmt.setInt(3, stu.getAge());  
			//执行指令
			pstmt.executeUpdate();
			
			System.out.println("添加成功!");
		} catch (SQLException e) {
			System.err.println("添加失败!" + sql);
			e.printStackTrace();  
		}finally{
			DbUtil.close(null, pstmt, conn);  
		}
	}
public static void main(String[] args) throws SQLException {
		StudentDao studentDao = new StudentDao();
		Student stu = new Student("王五","女",18);
		
		studentDao.addPreStu(stu);
}

----结果----
mysql驱动加载成功!

添加成功!

 

五、CRUD批量操作, 原理一样,实例 批量增加记录

Statement 批量添加

	// Statement 批量添加
	public void insertBatch(ArrayList<Student> list) throws SQLException{
		Connection conn = null;
		Statement stmt = null;
		String sql = null;
		
		try {
			conn = DbUtil.getConn();
			stmt = conn.createStatement();
			
			for(Student stu: list){
				sql =  "insert into student(name,sex,age) values('"+stu.getName()+"','"+stu.getSex()+"',"+stu.getAge()+")";
				stmt.addBatch(sql);   //将指令添加到批处理
			}
			
			stmt.executeBatch();  //批量执行
			System.out.println("添加成功");
		} catch (SQLException e) {
			System.err.println("添加失败!"+sql); 
			e.printStackTrace();
		} finally{
			DbUtil.close(null, stmt, conn); 
		}
	}

PreparedStatement 批量添加 

	// PreparedStatement 批量添加
	public void insertBatch(ArrayList<Student> list) {
		Connection conn = null;
		PreparedStatement pstmt = null;	
		String sql ="insert into student(name,sex,age) values(?,?,?)";
		
		try {
			conn = DbUtil.getConn();
			pstmt = conn.prepareStatement(sql);
			
			for (Student stu : list) {
				pstmt.setString(1, stu.getName());
				pstmt.setString(2, stu.getSex());
				pstmt.setInt(3, stu.getAge());
				//将指令添加到批处理
				pstmt.addBatch();
			}
			
			pstmt.executeBatch(); //批量执行
			System.out.println("添加成功");
		} catch (SQLException e) {
			System.err.println("添加失败!"+sql); 
			e.printStackTrace();
		} finally{
			DbUtil.close(null, pstmt, conn);  
		}			
	} 

测试: 

		StudentDao studentDao = new StudentDao();
		//模拟数据
		ArrayList<Student> list = new ArrayList<Student>();
				
		list.add(new Student("张三","女",20));
		list.add(new Student("李四","男",22));
		list.add(new Student("王五","男",23));
		studentDao.insertBatch(list);

----结果----
mysql驱动加载成功!

添加成功!

六、java JDBC事务处理

事务的基本概念:事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功

Connection 接口中提供了:

          setAutoCommit(),   // 设置数据库自动提交模式,改为手动提交

          commit(), rollback() ...

//DAO 转账  采用事务处理
public void tansfer(int fromId,int toId,double money){
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = "update card set money = money + ? where id = ?";
		
		try {
			conn = DbUtil.getConn();
			pstmt = conn.prepareStatement(sql);
			
			conn.setAutoCommit(false);    //设置数据库自动提交模式,改为手动提交
			
			//转出的卡
			pstmt.setDouble(1, -money); 
			pstmt.setInt(2, fromId);  
			pstmt.addBatch();   //加入批处理
			
			//转入的卡
			pstmt.setDouble(1, money);  
			pstmt.setInt(2, toId);  
			pstmt.addBatch();   //加入批处理
			
			int[] num = pstmt.executeBatch();    //返回值表示各条指令执行后数据表中受影响的记录条数
			
			if(num[0]!=1 || num[1]!=1){
				conn.rollback();   //回滚:撤销事务
				conn.setAutoCommit(true);  //恢复自动提交
				throw new DaoException("转账失败,卡号不存在!");
			}
			
			conn.commit();   //手动提交数据
			conn.setAutoCommit(true);  //恢复自动提交   
			System.out.println("转账成功");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
}


//Test 类

CarDao carDao = new CarDao();
carDao.tansfer(1001, 1002, 4000);

----结果----
mysql驱动加载成功!

转账成功

七、JDBC 调用存储过程和函数

在数据库中我们可以写一些存储过程和函数,来封装一些常用的SQL语句,存储过程和函数目的是为了可重复地执行操作数据库的sql语句的集合

主要区别就是函数必须有返回值(return),并且函数的参数只有 IN 类型存储过程 IN、OUT、INOUT 这三种类型。

  • 存储过程的返回值,可以有多个值
  • 函数的返回值,只有一个值

函数是可以嵌入在SQL中使用的,可以在SELECT等SQL语句中调用,而存储过程则不行。我们可以在数据库中创建一些常用的存储过程和函数,这样我们在数据访问层直接调用即可。这里记录一下使用JDBC调用存储过程和函数的方法

1. JDBC调用存储过程和函数

步骤:
1 通过 Connection 对象的 prepareCall() 方法创建一个 CallableStatement 对象的实例。在使用 Connection 对象的 prepareCall()方法时,需要传入一个String类型的字符串,该字符串用于指明如何调用存储过程
    函数: {?= call <procedure-name>[(<arg1>,<arg2>, ...)]}
    存过: {call <procedure-name>[(<arg1>,<arg2>, ...)]}

2 通过 CallableStatement 对象的 registerOutParameter() 方法注册 OUT 参数或者返回值参数类型
3 通过 CallableStatement 对象的 setXxx() 方法设定 ININOUT参数
若想将参数默认值设为 Null ,可以使用 setNull() 方法
4 通过 CallableStatement 对象的 execute() 方法执行存储过程
5 如果所调用的是带返回参数的存储过程,还需要通过 CallableStatement 对象的 getXxx() 方法获取其 OUT 或者返回值的值

2. 存储过程数据库操作(Navicat 操作)

    2.1 调用无参存储过程

存过:{call <procedure-name>[(<arg1>,<arg2>, ...)]}

drop procedure if exists p_student_select;
create procedure p_student_select()
begin
     select * from student;
end 

DAO:

	public List<Student> procedure(){
		List<Student> list = new ArrayList<Student>();

		Connection conn = null;
		CallableStatement call = null;
		ResultSet rs = null;
		
		try {
			conn = DbUtil.getConn();
			call = conn.prepareCall("{call p_student_select()}"); //调用存过
			
			rs = call.executeQuery(); //执行存过
			while(rs.next()) {
				//创建Student对象存放记录的值
				Student stu = new Student();
				stu.setId(rs.getInt("id"));
				stu.setName(rs.getString("name")); 
				stu.setSex(rs.getString("sex"));
				stu.setAge(rs.getInt("age"));
				list.add(stu);
			}
			System.out.println("存过调用成功!");
		} catch (SQLException e) {
			System.out.println("存过调用失败!");
			e.printStackTrace();
		} finally{
			DbUtil.close(null, call, conn);  
		}	
		return list;
	}


----test类----
    List<Student> list = (ArrayList<Student>) studentDao.procedure();
    for (Student student : list) {
	System.out.println(student);
    }

----结果----
存过调用成功!
Student [id=3, name=李四, sex=男, age=18]
Student [id=4, name=李四, sex=男, age=18]
Student [id=29, name=张三, sex=女, age=20]
Student [id=30, name=李四, sex=男, age=22]
Student [id=31, name=王五, sex=男, age=23]

    2.2 调用入参的存储过程

存过:

drop procedure if exists p_student_insert;
create procedure p_student_insert(IN p_name varchar(30), IN p_sex varchar(1))
begin
     insert into student(name,sex) values(p_name,p_sex);
end 

DAO:

	public void procedure(String name, String sex) {
		Connection conn = null;
		CallableStatement call = null;
		
		try {
			conn = DbUtil.getConn();
			call = conn.prepareCall("{call p_student_insert(?,?)}"); //调用存过
			call.setString(1, name);
			call.setString(2, sex);
			
			call.execute(); //执行存过
			System.out.println("存过调用成功!");
		} catch (SQLException e) {
			System.out.println("存过调用失败!");
			e.printStackTrace();
		} finally{
			DbUtil.close(null, call, conn);  
		}	
	}

----test类----
    studentDao.procedure("存过", "男");

----结果----
存过调用成功!

    2.3 调用出参存储过程

    存过:

drop procedure if exists p_student_count;
DELIMITER $$
create procedure p_student_count(INOUT p_name varchar(30), OUT p_count Integer(11))
begin
     select count(*) into p_count from student where name = p_name;
end 
$$
DELIMITER ;

DAO:

	public Integer procedure(String name) {
		Connection conn = null;
		CallableStatement call = null;
		Integer count = null;
		try {
			conn = DbUtil.getConn();
			call = conn.prepareCall("{call p_student_count(?,?)}"); 
			call.setString(1, name);
			call.registerOutParameter(2, java.sql.Types.INTEGER); //注册存储过程的out型参数类型;使用之前必须注册
			
			call.execute(); 
			count = call.getInt(2);	//获得存储过程的输出参数
			System.out.println("存过调用成功!");
		} catch (SQLException e) {
			System.out.println("存过调用失败!");
			e.printStackTrace();
		} finally{
			DbUtil.close(null, call, conn);  
		}	
		return count;
	}

----结果----
    Integer count = studentDao.procedure("李四");
    System.out.println(count);

----
mysql驱动加载成功!

存过调用成功!
3

3. 函数 数据库操作(Navicat 操作)

函数: {?= call <procedure-name>[(<arg1>,<arg2>, ...)]}

drop function if exists f_student_select;
DELIMITER $$
create function f_student_select(p_name varchar(30))
returns VARCHAR(30)
begin
    DECLARE p_count int;
    select count(*) into p_count from student where name = p_name;
    return CONCAT("函数返回记录数为: ",p_count);
end
$$
DELIMITER ;

DAO:

	public String function(String name) {
		Connection conn = null;
		CallableStatement call = null;
		String result = null;
		try {
			conn = DbUtil.getConn();
			call = conn.prepareCall("{?= call f_student_select(?)}"); 
			call.registerOutParameter(1, java.sql.Types.VARCHAR); //注册函数的返回值参数类型;使用之前必须注册
			call.setString(2, name);
			
			call.execute(); 
			result = call.getString(1);	//获得函数的返回值
			System.out.println("存过调用成功!");
		} catch (SQLException e) {
			System.out.println("存过调用失败!");
			e.printStackTrace();
		} finally{
			DbUtil.close(null, call, conn);  
		}	
		return result;
	}

----test----
	String result = studentDao.function("李四");
	System.out.println(result);

----结果----
mysql驱动加载成功!

存过调用成功!
函数返回记录数为: 3

猜你喜欢

转载自blog.csdn.net/qq_42402854/article/details/81275198