在工作中,程序员可能会需要用到很多数据库,若没有相应的工具,程序员每用到一个数据库就需要掌握一条与之对应的方法调用,当换数据库时,代码也需要做相应改动,这样极其不利于开发,效率很低,这时JDBC接口就应运而生。

JDBC(java Database Connectivity) java数据库连接,实际上JDBC是sun公司提供一套连接数据库的API

sun公司提供JDBC接口,让各个数据库厂商根据此接口写实现类(驱动),这样java程序员只需要掌握JDBC接口中的方法的调用,就可以访问任何数据,而且换数据库时代码不需要做任何的改动。

一、初步建立JDBC


1、建立一个普通Java工程

2、创建一个包,将java数据库连接的jar包导入
​​​​​​在这里插入图片描述

3、找到idea中的项目结构选项点击进入,找到libraries
在这里插入图片描述
在这里插入图片描述

4、进入libraries并找到“+”,后续照图示进行点击
在这里插入图片描述
在这里插入图片描述

5、找到之前导入的jar包,点击确定
在这里插入图片描述
在这里插入图片描述

6、点击应用后,确定。
在这里插入图片描述

7、先前导入的jar包可以打开了,我们可以使用其中的接口方法了
在这里插入图片描述
8、可以在idea中写数据库相关语句了

public class Demo01 {
    public static void main(String[] args) {
        //通过java来操作数据库

//        1.加载驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
//        2.获取链接
        Connection connection=null;
        try {
            connection=DriverManager.getConnection("数据库驱动地址","数据库用户名","数据库密码");
        } catch (SQLException e) {
            e.printStackTrace();
        }
//        3.获取对象  执行sql语句
        Statement statement=null;
        try {
            statement=connection.createStatement();
        } catch (SQLException e) {
            e.printStackTrace();
        }
//        4.执行sql
        try {
            boolean bo=statement.execute("sql语句");
        } catch (SQLException e) {
            e.printStackTrace();
        }
//        5.关闭数据库
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }
}

statement.execute(“sql语句”);可以执行所有sql语句 增删改查
statement.executeQuery(“查操作”);
statement.executeUpdate(“改操作”);

二、配置工具类与外部文件

在实际开发时,如果我们每用一次数据库就写一遍连接数据库的代码,这样是很浪费时间的,为了便于开发随去随用,我们可以把重复的一样的代码都封装在一个工具类中,每当我们要用时,直接引用即可。

而类似数据库驱动地址、数据库用户名、数据库密码这些变量,如果当我们要换数据库时,就需要对其做出调整,我们就需要在java代码中去找这些变量,这样也是很不方便的。这时我们可以把这些变量都封装在一个外部文件中,通过外部文件给java代码中这些变量赋上值,当我们要修改数据库时,只需修改外部文件中的内容即可,实现一种动态赋值。

工具类:

public class DBUtil {
    private static String driver;
    private static String url;
    private static String username;
    private static String password;
    static{
        Properties properties=new Properties();
        InputStream is=DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
        try {
            properties.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        driver=properties.getProperty("db.driver");
        url=properties.getProperty("db.url");
        username=properties.getProperty("db.username");
        password=properties.getProperty("db.password");
    }
    public static Connection getConnection() {
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Connection connection= null;
        try {
            connection = DriverManager.getConnection(url,username,password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
    public static void close(Connection connection) {
        if(connection!=null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

配置文件:
在这里插入图片描述
配置文件需要放在资源目录下才能被找到。
在这里插入图片描述

案例:查找用户

从数据库中拿取的数据可以通过类的包装来保存

包装类:


```java
public class DBemp {
    private int id;
    private String name;
    public DBemp(){

    }
    public DBemp(int id, String name){
        this.id=id;
        this.name=name;
    }
    public void setId(int id){
        this.id=id;
    }
    public int getId(){
        return id;
    }
    public void setName(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
    public String toString(){
        return "id="+id+"  name="+name;
    }
}

主方法:

public class GetUser {
    public static void main(String[] args) throws Exception {
        Connection conn= DBUtil.getConnection();
        Statement st=conn.createStatement();
        String s="select * from emp";
        ResultSet rs=st.executeQuery(s);
        List<DBemp> list=new ArrayList<>();
        while(rs.next()){
            int id=rs.getInt("id");
            String name=rs.getString("name");
            DBemp db=new DBemp(id,name);
            list.add(db);
        }
        System.out.println(list);
        DBUtil.close(conn);
    }
}

三、数据库连接池

每次用到数据库时,都涉及到了开启数据库–连接数据库–关闭数据库的流程,如果我们需要多次使用数据库时,重复做这个流程是十分耗费计算机性能的。我们可以借助数据库连接池来解决这个问题。

1、导入数据库连接池

导入数据库连接池的方法和导入JDBC的步骤基本一样,可根据图示进行操作:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
现在导入完成的是一个第三方的jar包,我们还需导入一个他依赖的jar包来为他提供一些他没有的类

因为导入步骤和dbcp完全一样,这里就不做演示了(偷个懒~~)
在这里插入图片描述
导入完成

2、设置数据库连接池

配置文件
在这里插入图片描述
主方法

public class DBUtil {
    private static String driver;
    private static String url;
    private static String username;
    private static String password;
    private static int initnum;
    private  static int maxNum;
    private static BasicDataSource basicDataSource;
    static{
        basicDataSource=new BasicDataSource();
        Properties properties=new Properties();
        InputStream is=DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
        try {
            properties.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        driver=properties.getProperty("db.driver");
        url=properties.getProperty("db.url");
        username=properties.getProperty("db.username");
        password=properties.getProperty("db.password");
        //连接池:
        initnum=Integer.parseInt(properties.getProperty("db.initnum"));
        maxNum=Integer.parseInt(properties.getProperty("db.maxunm"));
        basicDataSource.setDriverClassName(driver);
        basicDataSource.setUrl(url);
        basicDataSource.setUsername(username);
        basicDataSource.setPassword(password);
        basicDataSource.setMaxActive(maxNum);
        basicDataSource.setInitialSize(initnum);
    }
    public static Connection getConnection() {
        Connection connection= null;
        try {
            connection = basicDataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
    public static void close(Connection connection) {
        if(connection!=null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

四、通过maven构建JDBC

以上我们都是通过手动的方式来获取jar包并解压,操作后我们可以发现这种方式是十分麻烦的、而且很多jar包是存在依赖关系的,例如我们上面配置的commons-dbcp的jar包,需要在其他jar包的支持下才能正常使用,这时我们就面临了一个问题,当我们使用一个新的、我们从来没用过的jar包时,我们如何知道它是否需要依赖、需要依赖哪些jar包,如果让我们把所有jar包都记住,大家也都明白这是不可能的,若是每次使用jar都要上网上去搜索这个jar包的特性,也是十分耗时耗力的。

而Java为我们提供的项目管理工具maven可以很好的解决这个问题。我们只需要在maven中提供一个坐标,maven就会帮我们获取到这个jar包,并添加到项目中,无需我们自己操作配置了。而且引入maven后,maven就可以自动帮我们将当前jar包所依赖的其他所有jar包全部导入进来,也不需要我们自己去判断这个jar包需要哪些jar包了,节省了很大的精力,提升了我们项目的效率。

下面我们来演示一下通过maven来获取jar包。

1、创建一个maven工程

2、在pom.xml文件中导入所需依赖的坐标,刷新pom文件
在这里插入图片描述
3、我们可以在外部库中找到我们想要的jar包,代表这个项目需要的依赖已经被我们配置进去了,而且jar包需要的依赖也一并被配置。

案例:用户登录

工具类同上

封装类

public class Emp {
    private int password;
    private String username;
    public Emp(){

    }
    public Emp(String username,int password){
        this.password=password;
        this.username=username;
    }
    public void setPassword(int password){
        this.password=password;
    }
    public int getPassword(){
        return password;
    }
    public void setUsername(String username){
        this.username=username;
    }
    public String getUsername(){
        return username;
    }
    public String toString(){
        return "username="+username+" password="+password;
    }
}

主方法

public class Demo01 {
    public static void main(String[] args) throws SQLException {
        Connection con=HomeDBUtil.getConnection();
        Statement sta=con.createStatement();
        String st="select * from emp";
        ResultSet rs=sta.executeQuery(st);
        ArrayList<String> list=new ArrayList();
        while(rs.next()){
            String username=rs.getString("ename");
            int password=rs.getInt("empno");
            Emp emp=new Emp(username,password);
            list.add(emp.toString());
        }
        HomeDBUtil.close(con);
        Scanner sc=new Scanner(System.in);
        while(true){
            System.out.print("username=");
            String name=sc.next();
            System.out.print("password=");
            String password=sc.next();
            int sum=0;
            for(String s:list){
                sum++;
                if(s.equals("username="+name+" password="+password)){
                    System.out.println("登录成功");
                    break;
                }
                if(sum==list.size()){
                    System.out.println("用户名或密码错误");
                }
            }
        }
    }
}

此案例仅是浅用一下JDBC作为测试,严格的用户登录应更精密的查询,例如应该先查一下用户名,看数据库中是否有此用户,再看密码,判断密码是否一致。

五、sql注入

1、防止sql注入

sql注入是一种代码漏洞,程序员可以通过sql注入非法获取数据库中的信息。

例:用户登录
select * from user where username=‘张三’ and password=123456;

通过这个语句可以在数据库中查找是否有相应用户,判断是否可以登录。这时当我们在后面拼接一个字符串:

sql注入:
select * from user where username=‘张三’ and password=123456 or 1=1;

程序员只需要在sql语句后面拼接 or 1=1 就可以让这个语句成为一个恒成立的句子,这是十分危险,很容易造成数据库中数据被窃取,我们需要避免sql注入的发生。

为了防止sql注入的发生,我们可以使用预编译对象PreparedStatement

String st="select * from emp where ename=? and empno=?";
PreparedStatement ps=con.prepareStatement(st);
ps.setInt(2,7521);
ps.setString(1,"WARD");
ResultSet rs=ps.executeQuery();

在创建对象时就会对sql语句进行预编译,将sql语句的逻辑锁死,从而实现防止sql注入的作用。

只要sql语句中出现变量时,为了保证安全我们需要使用PreparedStatement

2、批量操作

PreparedStatement

//执行批量删除
        Connection con=HomeDBUtil.getConnection();
        String st="delete from userinfo where user_id=?";
        PreparedStatement ps=con.prepareStatement(st);
        for(int i=1;i<=3;i++) {
            ps.setInt(1, i);
            ps.addBatch();
        }
        ps.executeBatch();

Statement

//执行批量删除
        Connection con=HomeDBUtil.getConnection();
        Statement statement=con.createStatement();
        for(int i=0;i<3;i++){
            String st="delete from userinfo where user_id="+i;
            statement.addBatch(st);
        }
        statement.executeBatch();

每次执行到addBatch方法时,都会将当前执行的sql语句放在缓冲池,等待executeBatch()方法批量执行。

3、分页查询

public class Demo04 {
    public static void main(String[] args) throws SQLException {
        Scanner sc=new Scanner(System.in);
        Connection con=HomeDBUtil.getConnection();
        int pageSize=2;
        System.out.println("要第几页:");
        int num=sc.nextInt();
        String st="select * from emp limit ?,?";
        PreparedStatement ps=con.prepareStatement(st);
        int startLine=(num-1)*pageSize;
        ps.setInt(1,startLine);
        ps.setInt(2,pageSize);
        ResultSet rs=ps.executeQuery();
        while(rs.next()){
            
            int empno= rs.getInt("empno");
            String ename=rs.getString("ename");
            System.out.println("empno:"+empno+";ename:"+ename);
        }
        HomeDBUtil.close(con);
    }
}

第一个?表示请求第几页,第二个?表示一页有几条数据。

4、常规事务操作

事务相关方法

con.setAutoCommit(false);//关闭事务自动提交
con.setAutoCommit(true);//开启事务自动提交
con.commit();//提交事务
con.rollback();//回滚事务

如果自动提交关闭了,我们需要手动提交。

5、获取自增主键

PreparedStatement ps=con.prepareStatement(st, Statement.RETURN_GENERATED_KEYS);

Statement.RETURN_GENERATED_KEYS 指的是能返回当前表的自增主键

ResultSet rs=ps.getGeneratedKeys();

getGeneratedKeys()方法能获取刚刚插入的自增主键,若是批量插入,就会获取批量插入的所有自增主键。

6、获取元数据

能够获取数据库相关的信息

//得到数据库的元数据
        Connection conn=DBUtil.getConnection();
        Statement stat=conn.createStatement();
        DatabaseMetaData dbmd = conn.getMetaData();
        System.out.println("数据库版本:"+ dbmd.getDriverVersion());
        System.out.println("用户名:"+ dbmd.getUserName());
        System.out.println("数据库地址:"+ dbmd.getURL());
        System.out.println("数据库厂商:"+ dbmd.getDatabaseProductName());

能够获取表相关的信息

//得到表相关的源数据
        Connection conn=DBUtil.getConnection();
        Statement stat=conn.createStatement();
        ResultSet rs = stat.executeQuery("select * from emp");
        ResultSetMetaData rsmd = rs.getMetaData();
        //得到表的字段数量
        int count = rsmd.getColumnCount();
        for (int i = 0; i < count; i++) {
            System.out.println("字段名" +rsmd.getColumnName(i+1));
            System.out.println("字段类型" +rsmd.getColumnTypeName(i+1));
        }

六、在哪儿下载jar包和获取依赖坐标

下载jar包__获取依赖坐标

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐