JDBC:Java Data Base Connectivity(Java连接数据库)
JDBC其实就是Java定义的一套和数据库建立连接的规范(接口),各家数据库厂商,想要Java去操作各家数据库,必须实现这套接口,我们把数据库厂商写的这套实现类,称之为数据库驱动。
一、JDBC快速入门
1.导入数据库的驱动jar包 2.加载驱动jar包 3.获取连接对象 4.获取操作对象 5.开始操作 6.释放资源
1.JDBC执行DML语句
public static void main(String[] args) throws Exception {
//1.导入jar包,并依赖
//2.加载驱动jar包,通过反射
Class.forName("com.mysql.jdbc.Driver");
//3.获取连接对象
/**
URL:统一资源定位符
协议://IP:端口/具体的资源路径 "https://home.firefoxchina.cn/"
主协议:子协议://ip:端口/资源 jdbc:mysql://localhost:3306/mydb
*/
String url="jdbc:mysql://localhost:3306/mydb";
String username="root";
String password="123456";
Connection connection = DriverManager.getConnection(url, username, password);
//4.获取操作对象
Statement statement = connection.createStatement();
//5.执行SQL语句
String sql="insert into user(username,password) values('张三','123456')";
int i = statement.executeUpdate(sql);
//返回值i代表影响的行数
if(i>0){
System.out.println("插入成功");
}else{
System.out.println("插入失败");
}
//释放资源
connection.close();
statement.close();
}
2.几个类的介绍
1.Class.forName(“com.mysql.jdbc.Driver”);加载驱动
可以省略不写。注册驱动这个动作是Driver里面有个静态代码块在做
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
2.类DriverManager
Java提供的管理一组JDBC驱动程序的基本服务
3.接口Connection
试图建立到给定数据库URL的连接
4.接口Statement
用于执行静态SQL语句并返回他所生成结果的对象
3.JDBC执行DQL语句
ResultSet结果集对象,执行查询语句后,查询的结果封装在结果集对象里面。表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。
ResultSet对象具有指向其当前数据行的光标。最初,光标被置于第一行之前。
next()方法将光标移动到下一行,该方法在ResultSet对象没有下一行时返回false
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/mydb";
String username="root";
String password="123456";
Connection connection = DriverManager.getConnection(url, username, password);
Statement statement = connection.createStatement();
String sql="select * from user";
ResultSet resultSet = statement.executeQuery(sql);
ArrayList<User> list = new ArrayList<>();
//取出结果集中的对象,既可以使用列号,也可以使用列名
while(resultSet.next()){
String name = resultSet.getString(2);
String word = resultSet.getString(3);
//把从数据库查询出来的零碎数据,封装起来,以便其他地方使用
User user = new User(name, word);
list.add(user);
}
System.out.println(list);
connection.close();
statement.close();
resultSet.close();
}
DML 增删改 DQL查询表中数据
statement.execuUpdate(sql)执行DML语句,用来对表中数据进行增删改。返回值是影响的行数
statement.execuQuery(sql)执行DQL语句
statement.execu(sql)执行任何SQL语句,如果第一个结果为 ResultSet 对象,则返回 true;如果其为更新计数或者不存在任何结果,则返回 false
4.预编译操作对象PrepareStatement
在安全方面防止SQL注入
使用步骤:
1.conn.prepareStatement(sql);
2.sql语句中的字段的值用?占位
3.给sql语句中的问号赋值
//sql语句中的值全部用 ? 问号占位
String sql="select * from user where username=? and password=?";
//获取一个预编译操作对象 PreparedStatement,把SQL语句给给这个预编译操作对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//给?赋值 参1:问号的顺序,从1开始 参2:问号的值
preparedStatement.setString(1,name);
preparedStatement.setString(2,word);
ResultSet resultSet = preparedStatement.executeQuery();//不要在传入SQL语句
二、登录的一个小案例
1.使用操作对象createStatement
利用拼串的方式将用户名,密码和数据库中的用户名,密码进行比对
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名");
String name = sc.nextLine().trim();
System.out.println("请输入密码");
String word = sc.nextLine().trim();
//从数据库中查询用户名与密码和用户输入的进行比对
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "101721");
Statement statement = connection.createStatement();
String sql="select * from user where username='"+name+"' and password='"+word+"'";
ResultSet resultSet = statement.executeQuery(sql);
//判断有没有登录成功
if(resultSet.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
}
但是,Sql注入,这样也能登录成功。
String name="1 'or' 1 '=' 1";
String word="1 'or' 1 '=' 1";
2.使用操作对象prepareStatement
预编译操作对象,提前编译sql语句。能够防止sql注入。
public static void main(String[] args) throws ClassNotFoundException, SQLException {
String name="1 'or' 1 '=' 1";
String word="1 'or' 1 '=' 1";
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "101721");
//我们通过createStatement()获取出的这个操作对象,去执行SQL语句,这个SQL语句有时会拼串,不能防止SQL注入
//为了防止SQL注入,我们可以使用另一个操作对象
//编写SQL语句, 参数拿?占位 注意:?是英文?
String sql="select * from user where username=? and password=?";
//prepareStatement预编译操作对象,可以提前编译sql语句,能够防止SQL注入
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//给?赋值
preparedStatement.setString(1,name);
preparedStatement.setString(2,word);
ResultSet resultSet = preparedStatement.executeQuery();//不要在传入SQL语句
if(resultSet.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
}
三、批处理
插入大量数据时,建议使用批处理来做
statement.addBatch();//添加批处理
statement.executeBatch();//执行批处理
statement.clearBatch();//清空批处理
public static void main(String[] args) throws Exception {
//我们有大量的数据要插入到数据库中
ArrayList<User> list = new ArrayList<>();
for(int i=2;i<=8;i++){
User user = new User("小可爱", "123");
list.add(user);
}
//将数据插入到数据库当中
Connection connection = JDBCUtils.getConnection();
String sql="insert into user(username,password) values(?,?)";
PreparedStatement statement = connection.prepareStatement(sql);
for (User user : list) {
statement.setString(1,user.getUsername());
statement.setString(2,user.getPassword());
statement.addBatch();//添加批处理
}
statement.executeBatch();//执行批处理
statement.clearBatch();//清空批处理
JDBCUtils.setClose(connection,statement);
}
四、JDBC调用存储过程和自定义函数
1.调用存储过程
给输入参数赋值; 注册输出参数; 获取输出参数
Connection connection = JDBCUtils.getConnection();
//获取调用存储过程的一个操作对象
//{call <procedure-name>[(<arg1>,<arg2>, ...)]} -- 调用存储过程的SQL语句
String sql="{call mypro(?,?)}";
CallableStatement callableStatement = connection.prepareCall(sql);
//1.给输入参数赋值
callableStatement.setInt(1,6);
//2.注册输出参数
callableStatement.registerOutParameter(2,Types.INTEGER);
//3.执行
callableStatement.execute();
//4.获取结果
int r = callableStatement.getInt(2);
System.out.println(r);
JDBCUtils.setClose(connection,callableStatement);
2.调用自定义函数
Connection connection = JDBCUtils.getConnection();
String sql="{?=call testFun(?)}";
CallableStatement callableStatement = connection.prepareCall(sql);
//设置输入参数
callableStatement.setInt(2,7902);
//注册输出参数
callableStatement.registerOutParameter(1, Types.INTEGER);
callableStatement.execute();
//获取返回的结果
int i = callableStatement.getInt(1);
System.out.println("结果是:"+i);
//释放资源
JDBCUtils.setClose(connection,callableStatement);
五、获取自增长键
1.要获取自增长键的值 需要在获取操作对象时声明一个参数 Statement.RETURN_GENERATED_KEYS
2.当数据插入成功后,就可以取出这个自增长键的值
Connection connection = JDBCUtils.getConnection();
String sql="insert into user(username) values(?)";
//Statement.RETURN_GENERATED_KEYS表示返回自增长键的值
PreparedStatement preparedStatement = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1,"张学友");
preparedStatement.execute();
//获取自增长键
ResultSet generatedKeys = preparedStatement.getGeneratedKeys();
int id=0;
while(generatedKeys.next()){
id = generatedKeys.getInt(1);
}
if(id>0){
System.out.println("注册成功");
}else{
System.out.println("注册失败");
}
六、读取配置文件
1.Properties读取配置文件
Properties properties = new Properties();
properties.load(new FileReader("JDBC.properties"));
//键找值
Class.forName(properties.getProperty("className"));
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
2.读取src目录下的配置文件
- Java提供的一个工具类,可以读取src目录下的文件
ResourceBundle这个工具类,读取配置文件,有两点要求
(1)配置文件要在src目录下,后缀名必须为.properties
(2)读取配置文件时,后缀名.properties不要写
ResourceBundle bundle = ResourceBundle.getBundle("JDBC");
//键找值
String className = bundle.getString("className");
String url = bundle.getString("url");
String username = bundle.getString("username");
String password = bundle.getString("password");
- getClassLoader().getResourceAsStream();
InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("JDBC.properties");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
String[] split = bufferedReader.readLine().split("=");
System.out.println(split[0]);
System.out.println(split[1]);