个人java学习路线----JDBC

介绍

JDBC: Java DataBase Connectivity (Java语言连接数据库)
本质是sun制定的一套接口
接口都有调用者和实现者
面向接口调用,面向接口写实现类,这都属于面向接口编程
面向接口编程是为了解耦合

JDBC编程六步

第一步:注册驱动(告诉Java程序,即将要连接的是哪个品牌 的数据库)
第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完一定要关闭通道)
第三步:获取数据库操作对象(专门执行sql语句的对象)
第四步:执行sql语句(DQL DML)
第五步:处理查询结果集(第四步执行了select才有这步)
第六步:释放资源(java和数据库之间属于进程通信,使用完必须关闭通道)

初次使用

public class JDBCTest1{
	public static void main(String[] args){
		Statement stmt=null;
		Connection conn=null;
		try{
			//1-(1-6为JDBC六步)注释掉的还有oracle相关协议等
			DriverManager.registerDriver(new com.mysql.jdbc.Driver());
			//DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
			//2
			String url="jdbc:mysql://127.0.0.1:3306/xxx";
			//String url="jdbc:oracle:thin:@localhost:1521:orcl";
			String user="root";
			String password="root";
			conn=DriverManager.getConnection(url,user,password);
			System.out.println("sql----->"+conn);
			//3
			stmt=conn.createStatement();
			//4 
			String sql ="insert into dept2(deptno,dname,loc) values(50,'人事部门','北京')";
			//专门执行DML语句的(insert delete update)
			//返回值是“影响数据库中的记录条数”
			int count=stmt.executeUpdate(sql);
			System.out.println(count==1?"save success":"save failed");					
		}catch(SQLException e){
			e.printStackTrace();
		}finally{
			//6 释放资源
			try{
				if(stmt != null){
					stmt.close();
				}
			}catch(SQLException e){
			e.printStackTrace();
			}
			try{
				if(conn != null){
					conn.close();
				}
			}catch(SQLException e){
			e.printStackTrace();
			}
		}		
	}
}

注册驱动升级

com.mysql.jdbc.Driver()方法中含有注册驱动的静态代码块,只需类加载就行,方便通过反射机制,操作properties文件,容易修改使用

			//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
			Class.forName("com.mysql.jdbc.Driver");

运用poperties文件:
项目下建立peoperties文件:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/数据库名
user=root
password=root

连接数据库改进:

public class JDBCTest4{
	public static void main(String[] args){
		ResourceBundle bundle=ResourceBundle.getBundle("jdbctest4");	
		String driver=bundle.getString("driver");
		String url=bundle.getString("url");
		String user=bundle.getString("user");
		String password=bundle.getString("password");
		Connection conn=null;
		Statement stmt=null;
		try{
			Class.forName(driver);
			conn=DriverManager.getConnection(url,user,password);
			stmt=conn.createStatement();
			String sql="insert into dept2(deptno,dname,loc) values(50,'wuliao','jialidun')";
			int count=stmt.executeUpdate(sql);
			System.out.println(count==1?"insert success":"insert failed");
		}catch(SQLException e){
			e.printStackTrace();
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		}finally{...}//省略
	}
}

模拟用户登录

ps:数据库相关改了

public class JDBCTest1 {
    public static void main(String[] args) {
        //初始化界面
        Map<String,String> userLoginInfo = initUI();
        //验证用户名密码
        boolean loginSuccess=login(userLoginInfo);
        System.out.println(loginSuccess?"登录成功":"登录失败");
    }

    /**
     * 用户登录
     * @param userLoginInfo  用户登录信息
     * @return  false 表示登录失败,true表示登录成功
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        boolean loginSuccess=false;
        //JDBC代码
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        try {
            //1注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2获取连接
            conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx","root","root");
            //3获取数据库操作对象
            stmt=conn.createStatement();
            //4执行sql
            String sql="select * from t_user where loginName='"+userLoginInfo.get("loginName")+"' and loginPwd='"+userLoginInfo.get("loginPwd")+"'";
            /*该命令有bug,当输入任意用户名密码后,在密码后加(' or 'xxx'='xxx)   ,因为该sql语句会编入mysql中,就变成了where ...and... or true=true,必定成功*/
            rs=stmt.executeQuery(sql);
            //5处理结果集
            if(rs.next()){
                loginSuccess=true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            //6释放资源
           //....省略
        }
        return loginSuccess;
    }

    /**
     * 初始化用户界面
     * @return 用户输入的用户名密码等信息
     */
    private static Map<String, String> initUI() {
        Scanner s=new Scanner(System.in);
        System.out.print("用户名:");
        String loginName=s.nextLine();

        System.out.print("密码:");
        String loginPwd=s.nextLine();

        Map<String,String> userLoginInfo =new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);

        return userLoginInfo;
    }
}

sql注入问题和PerparedStatement接口

模拟用户登录代码中说了有sql注入问题,即在登录输入数据时我们可以适当的输入sql语言从而破坏原有sql语言结构。
为了防止用户输入sql语言出现了PerparedStatement接口,PerparedStatement会预编译sql,用户输入的数据始终不会破坏原sql语言结构。

public class JDBCTest2 {
    public static void main(String[] args) {
        Map<String,String> userLoginInfo = initUI();
        boolean loginSuccess=login(userLoginInfo);
        System.out.println(loginSuccess?"登录成功":"登录失败");
    }
    private static boolean login(Map<String, String> userLoginInfo) {
        boolean loginSuccess=false;
        Connection conn=null;

        //*
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/xx","root","root");

            //*
            String sql="select * from t_user where loginName=? and loginPwd=?";//?占位符
            ps=conn.prepareStatement(sql);
            ps.setString(1,userLoginInfo.get("loginName"));//占位符传值
            ps.setString(2,userLoginInfo.get("loginPwd"));
            rs=ps.executeQuery();
            if(rs.next()){
                loginSuccess=true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
           //...省略
        }
        return loginSuccess;
    }
    private static Map<String, String> initUI() {
        Scanner s=new Scanner(System.in);
        System.out.print("用户名:");
        String loginName=s.nextLine();
        System.out.print("密码:");
        String loginPwd=s.nextLine();
        Map<String,String> userLoginInfo =new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);
        return userLoginInfo;
    }
}

需要sql注入时举例

一般我们只用PerparedStatement类就行。
但有时我们也需要Statement,例如需要用户输入数据完成升序降序排序时需要sql注入,否则完不成需求

增删改

注意方法就行

public class JDBCTest4 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx","root","root");
            String sql="update  dept2 set dname=? ,loc=? where deptno=?";
            ps=conn.prepareStatement(sql);
            ps.setInt(3,50);
            ps.setString(1,"wudigongsi");
            ps.setString(2,"chaodadifang");
            int count=ps.executeUpdate();
            System.out.println(count);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
           //....
        }
    }
}

JDBC事务

事务是必须的

/*
* JDBC中事务时自动提交的,只要执行任意一条DML语句,则自动提交一次
* 但在实际的业务中,通常都是N条DML语句共同联合才能完成的,必须保证他们这些DML语句在同一个事务中同时成功或同时失败
* 以下程序验证JDBC只要执行任意一条DML语句,就提交一次
* */
public class JDBCTest5 {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx","root","root");
            String sql="update dept2 set dname=? where deptno=?";
            ps=conn.prepareStatement(sql);
            ps.setInt(2,50);
            ps.setString(1,"wudigongsi");
            int count=ps.executeUpdate();
            System.out.println(count);
            ps.setString(1,"asdsad");
            ps.setInt(2,40);
            count=ps.executeUpdate();
            System.out.println(count);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
       	 //...
        }
    }
}

工具类DBUtil

到这我们会发现我们写JDBC时,会有很多重复的代码,我们完全可以创建一个公共类来减少代码的重复,这里进行初步的抽取

/**
 * JDBC工具类,简化JDBC编程
 */
public class DBUtil {
    private DBUtil(){}

    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws SQLException{
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx","root","root");
    }

    /**
     * 关闭资源
     * @param conn  连接对象
     * @param ps  数据库操作对象
     * @param rs  结果集
     */
    public static void close(Connection conn, Statement ps, ResultSet rs){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

这时我们写JDBC就会方便很多:

public class JDBCTest7 {
    public static void main(String[] args) {
        Connection conn= null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            conn=DBUtil.getConnection();
            String sql="select ename from emp where ename like ?";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"_A%");
            rs=ps.executeQuery();
            while(rs.next()){
                System.out.println(rs.getString("ename"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            DBUtil.close(conn,ps,rs);
        }
    }
}

开启事务,专门进行查询,并且使用行级锁/悲观锁,锁住相关的记录

简单看一下

public class JDBCTest81 {
    public static void main(String[] args) {
        Connection conn= null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try {
            conn= DBUtil.getConnection();
            conn.setAutoCommit(false);
            String sql="select ename,job,sal from emp2 where job=? for update ";
            ps=conn.prepareStatement(sql);
            ps.setString(1,"MANAGER");
            rs=ps.executeQuery();
            while (rs.next()){
                System.out.println(rs.getString("ename")+","+rs.getString("job")+","+rs.getDouble("sal"));
            }
            conn.commit();
        } catch (SQLException throwables) {
            if(conn !=null){
                try {
                    conn.rollback();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            throwables.printStackTrace();
        }finally {
            DBUtil.close(conn,ps,rs);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值