1.对数据库调用的不同方式

java.sql包下有3个接口
image

  • Statement:用于执行静态SQL语句。
  • PreparedStatement:SQL语句被预编译并存储在此对象中。
  • CallableStatement:用于执行SQL存储过程。

image

2.使用Statement操作数据库

获取到connect对象后,创建statement对象,执行sql

Statememt st = connect.createStatememt();
ResultSet rs = st.executeQuery("select * from table");

(1)使用Statememt操作表的弊端

  • 对于有参数的SQL语句需要拼串。
String sql = "SELECT user,password FROM user_table WHERE USER = '" + userName
+ "' AND PASSWORD = '" + password
+ "'";
  • 存在SQL注入问题

SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' = '1') ,从而利用系统的 SQL 引擎完成恶意行为的做法。

public class StatementTest {
    @Test
    public void login(){
        Scanner scanner = new Scanner(System.in);
        System.out.println("用户名:");
        String userName = scanner.nextLine();
        System.out.println("密 码:");
        String password = scanner.nextLine();

        String sql = "SELECT user,password FROM user_table WHERE user = '"+userName+"' AND password = '"+password+"'";
        User user = getUser(sql, User.class);
        if (user!=null){
            System.out.println("登录成功!");
        }else {
            System.out.println("用户名或密码错误!");
        }
    }

    public <T> T getUser(String sql,Class<T> clazz){
        //放到外面是因为在finally中要用
        T t = null;
        Connection connect = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            //1.加载配置文件
            InputStream is = StatementTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
            Properties pros = new Properties();
            pros.load(is);

            //2.读取配置文件
            String user = pros.getProperty("user");
            String password = pros.getProperty("password");
            String url = pros.getProperty("url");
            String driverClass = pros.getProperty("driverClass");

            //3.加载驱动
            Class.forName(driverClass);

            //4.获取连接
            connect = DriverManager.getConnection(url, user, password);

            //5.创建statement对象
            st = connect.createStatement();

            //6.执行sql,得到结果集
            rs = st.executeQuery(sql);

            //7.获取结果集的元数据
            ResultSetMetaData rsmd = rs.getMetaData();

            //有多少列
            int columnCount = rsmd.getColumnCount();

            if (rs.next()){
                t =clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    //1.获取列别名
                    String columnName = rsmd.getColumnLabel(i+1);

                    //2.根据列名获取数据
                    Object columnVal = rs.getObject(columnName);

                    //3.将得到的数据封装进对象
                    Field field = clazz.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,columnVal);
                }
                return t;
            }

        } catch (Exception e) {
            e.printStackTrace();
		} finally {
		//关闭资源
		JDBCUtils.closeResource(conn, ps, rs);
	}
	return null;
	}
}

3.ResultSet和ResultSetMetaData

(1)ResultSet

执行executeQuery()方法返回结果集,是一个ResultSet对象,相当于一张数据表,有一个指针指向第一行记录。使用next()方法检测下一行是否有效,若有效返回true并移动到下一行。相当于Iterator对象的hasNext()和next()方法的结合体。
当指向一行时,通过索引或列名获取该列的值。getInt(1),getString("name")

Java与数据库交互涉及到的相关Java Api中的索引都从1开始。

image

(2)ResultSetMetaData

用于获取ResultSet对象中列的类型和属性信息的对象

ResultSetMetaData rsmd = resultSet.getMetaData();

常用方法

getColumnName(int column);	//获取指定列名称
getColumnLabel(int column);	//获取指定列别名,没有别名则获取列名
getColumnCount();	//有多少列
getColumnTypeName(int column);	//列的数据库类型名称
getColumnDisplaySize(int column); 	//列的最大标准宽度,以字符为单位
isNullable(int column);	//列中的值是否可以为null
isAutoIncrement(int column);	//是否为指定列进行自动编号

例如表结构
image

SQL语句为,如果balance不选,则columnCount为2

SELECT user,password,balance FROM user_table WHERE user = 'AA' AND password = '123456'

image

两者之间的联系
image

4.PrepareStatement操作数据库

image

PrepareStatement是Statement的子接口。

public interface PreparedStatement extends Statement

获取对象,表示一条预编译过的SQL语句

PrepareStatement ps = connect.prepareStatement(sql);

SQL语句中的参数用英文问号表示,调用prepareStatement对象的setXxx(1,value)方法设置这些参数,1表示索引(从1开始),value表示值。

    @Test
    public void login(){
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String user = scanner.nextLine();
        System.out.print("请输入密码:");
        String password = scanner.nextLine();

//        String sql = "SELECT user,password FROM user_table WHERE user = ? AND password = ? ";
        String sql = "SELECT user,password FROM user_table WHERE user = ? and password = ?;";
        User returnUser = getUser(User.class, sql, user, password);
        if (returnUser!=null){
            System.out.println("登录成功");
        }else {
            System.out.println("用户名或密码错误");
        }
    }

    public <T> T getUser(Class<T> clazz,String sql,Object... args){
        Connection connect = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            connect = JDBCUtil.getConnection();
            ps = connect.prepareStatement(sql);
            //遍历参数并设置值
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i+1,args[i]);
            }
            //ps.execute();//增删改执行这个
            rs = ps.executeQuery();     //产生单个结果集
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();
            if (rs.next()){
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {

                    Object columnValue = rs.getObject(i + 1);   //列值
                    String columnLabel = rsmd.getColumnLabel(i + 1);    //列别名

                    //通过反射获取对象属性
                    Field field = clazz.getDeclaredField(columnLabel);

                    //允许客户端拥有超级权限,不会去检查Java语言权限控制(private之类的)
                    field.setAccessible(true);
                    field.set(t,columnValue);      //给对象t的属性设值
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.closeResource(connect,ps,rs);
        }
        return null;
    }

5.其他

(1)ORM思想

  • 一张数据库表对应一个Java类
  • 表中的一条记录对应Java类的一个对象
  • 表中的一个字段对应Java类的一个属性

写sql时注意别名

(2)Java与SQL对应数据类型

Java类型 SQL类型
boolean BIT
byte TINYINT
short SMALLINT
int INTEGER
long BIGINT
String CHAR,VARCHAR,LONGVARCHAR
byte array BINARY,VAR BINARY
java.sql.Date DATE
java.sql.Time TIME
java.sql.Timestamp TIMESTAMP

(3)PrepareStatement的好处

① 可以防止SQL注入
② 预编译SQL语句可以重复使用,不同参数也不用重新编译(Statement每次执行都需要)
③ 不需要拼串

参考
1.field.setAccessible(true) 简介
2.PreparedStatement是如何防止SQL注入的?

原文地址:http://www.cnblogs.com/zhishu/p/16874755.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性