JDBC(Java Database connectivity)

数据库连接步骤:
1.加载数据库驱动
将驱动所需要的jar包加入到工程的project build path中
加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
要记住驱动连接的格式:
DRIVER = "com.mysql.jdbc.Driver";
记忆的时候可以联想一下这个驱动字符串是域名的导致,也就是说域名应该是Driver.jdbc.mysql.com

在加载这个数据库驱动的时候会跑出ClassNotFoundException这个异常
2.获得数据库连接
Connection conn = DrivrerManager.getConnection
("jdbc:mysql://localhost:3306/dbname","username","password";
jdbc:mysql://localhost:3306/dbname为连接字符串URL
URL也可以这么写
URL = "jdbc:mysql://ipaddress:3306/dbname";
这个代表连接到主机IP地址为ipaddress的3306端口的dbname数据库
当连接本地主机的默认3306端口号的时候可以这么写:
URL = "jdbc:mysql:///dbname"

3.执行sql语句
String sql = "";
Statement stat = conn.createStatement();
stat.executeUpdate(sql);
这条语句只能执行insert、update、delete语句,返回值类型为int,代表受影响的行数。
stat.executeQuery(sql);
这条语句执行select语句,返回类型为ResultSet类型,代表查询到的结果集。
对于insert、update、delete语句,又是想要获得结果集对象可以使用带两个参数的executeUpdate()方法,出入一个静态的值Statement.RETURN_GENERATED_KEYS

这时可以使用getGenerateKeys()方法来获得ResultSet结果集对象,通过rs.getInt(indexColumn)来获得主键的值。有时候程序在执行insert、Update、delete语句时需要知道主键的值。

4.关闭资源
rs.close();
stat.close();
conn.close();

在2、3、4操作中会跑出异常,使用try...catch语句捕获异常
这时候存在一种情况当sql拼写错误的时候,在执行的时候会抛出异常,但是conn资源和stat资源已经建立,但是并没有被干必掉,长此以往就会导致数据库可用连接减少。因此在关闭的时候在try...catch...语句中的finally语句块中执行要关闭资源的操作,在关闭资源的时候还要先判断资源是否为null,当不是null的时候再关闭。并且关闭资源的顺序应与建立资源的顺序相反。
example:
try {
if(rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

}

在实际生产环境中是不会使用这种方式的,当使用这个方式进行insert语句的时候就得拼SQL,这种做法相当的痛苦,因此不适用这种方式,并且这种方式从安全角度讲容易被SQL注入。

String sql = "SELECT id,username,PASSWORD,eanble,money FROM t_account WHERE
username = '"+name+"' AND PASSWORD = '"+pwd+"'";
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery(sql);

当知道用户名的时候就可以使用这种方式在随意输入密码的时候登录账户。
并且当输入用户名时的扫描器是以readLine()这样的方法读入的时候,还可以在输入任意用户名的情况下浏览该网站的任何数据:
空格'or 1=1#

 

 

PreparedStatement:

因此在使用的时候出现了PreparedStatement,这个类是Statement的子类。
优点:
1.对SQL语句进行预编译处理,执行速度快
2.防止SQL注入
3.代码阅读性提高
PreparedStatement stat = conn.PreparedStatement(sql);
由于是预编译,需要在执行之前就将sql语句传进去。并且stat的获得方式不再是createStatement(),而是conn.PreparedStatement();

在sql语句中传入的值使用 ? 来表示,
String sql = "insert into tablename value(字段1,字段2,字段3...) values(?,?,?...)";
在执行之前要给这些问号赋值
stat.setType(1,value1);
Stat.setType(2,value2);
stat.setType(3,value3);

Type为要传入值的类型,1、2、3代表为第几个问号赋值,value为字段值。

 

 

 

DAO(Data Access Object)数据访问对象
每个DAO封装了对一个实体类(entity)的CRUD操作。实体类跟数据库中的表相对应,实体类的属性相当于表中的字段,实体类的对象相当于表中的一条记录。
因此在创建实体类的时候根据表中的字段创建实体类的属性,根据表中的记录来创建对象。

以面向对象的角度来进行数据库的CRUD操作,创建一个实体类的DAO类,来对这个实体类进行CRUD操作。
有了DAO之后,就不允许在DAO以外的地方出现JDBC的程序。

 

 

 

DAO(Data Access Object)数据访问对象
每个DAO封装了对一个实体类(entity)的CRUD操作。实体类跟数据库中的表相对应,实体类的属性相当于表中的字段,实体类的对象相当于表中的一条记录。
因此在创建实体类的时候根据表中的字段创建实体类的属性,根据表中的记录来创建对象。

以面向对象的角度来进行数据库的CRUD操作,创建一个实体类的DAO类,来对这个实体类进行CRUD操作。
有了DAO之后,就不允许在DAO以外的地方出现JDBC的程序。

 

 

工具类DbHelp(写帮助类或工具类一定要注意中立性,什么类和方法都可以直接调用),创建executeUpdate()方法,来执行insert、Update、delete操作。
将释放资源和获得数据库连接写成单独的放在放在工具类中。
在创建executeQuery()方法的时候要传入sql语句,及sql的参数,sql的参数使用不定项参数的形式Object... params,创建类型为Object类型的不定项参数代表可以穿进去任何类型的参数。在获得结果集的时候为了保证工具类的中立性和通用性建立一个RowMapper的接口,所有的实现类都继承该接口,然后实现接口中的rowMapper方法,来将结果集中的数据已Object的形式返回出来,在各自的实体类的DAO中强制类型转换为对应的实体类对象。同理也可以查询所有的实体类,方法名queryForList(),返回一个List集合,集合中的元素为对应表中的实体类对象。

 

内部类:

注意:
一个Java文件中可以有多个类,但是只能有一个类是public来修饰的,但是不推荐这样写,因为这样在调用的时候不利于阅读,当这样写的时候编译器实际上会编译出两个class文件一个是public修饰的类,一个是没有访问修饰符修饰的类。

  1. 内部类:(在一个类的内部声明的类成为内部类)
    public class Outer {
    private String name = "tom";
    public void outerMethod() {
    System.out.println(name);
    System.out.println("outermethod");
    }

    public class Inner {
    private String name = "jack";
    public void innerMethod() {
    System.out.println(name);
    System.out.println(Outer.this.name);
    System.out.println("innerMethod");
    }
    }
    }

    当内部类的访问修饰符为private的时候,内部类只能在外部类的内部使用,使用外部类时不知道内部类的存在
    内部类的访问修饰符可以为public,每个类都有各自的属性和方法。内部类的创建需要外部类对象来调用内部类的构造方法
    内部类可以使用外部类中的私有实例变量
    public class Outer {
    private String name = "Tom";
    public void hi() {
    System.out.println("Hello,This is Outer Class");
    }
    public class Inner {
    public void sayHello() {
    System.out.println("Hello," + name);
    }
    }
    }
    可以在外部类中创建内部类的对象,并调用内部类的方法
    public class Outer {
    private String name = "Tom";
    public void hi() {
    Inner inner = new Inner();
    inner.age = 20;
    inner.sayHello();
    }
    private class Inner {
    private int age = 10;
    public void sayHello() {
    System.out.println("Hello," + Outer.this.name + "\t" + age);
    }
    }
    }
    内部类可以直接调用外部类的方法,但是外部类不能直接调用内部类的方法
    内部类的实例化
    Outer outer = new Outer();
    Inner inner = outer.new Inner();
    inner.innerMethod();
    当内部类的访问修饰符为private的时候,内部类对象的创建就只能在外部类的内部创建内部类对象。

  2. 静态内部类(使用static来修饰的内部类)

    public class Outer {
    public void outerMethod() {
    System.out.println("outerMethod");
    }
    public static class Inner {
    System.out.println("innerMethod");
    }
    }

    静态内部类的创建不普通内部类的创建不太一样,需要使用静态的方式来创建静态内部类对象。
    在静态内部类中,当内部类调用了外部类的使用static修饰的方法和属性的时候,外部类不能调用内部类的方法,因为这样会发生堆栈溢出,会造成死循环
    Outer.Inner inner = new Outer.Inner();
    inner.innerMethod();

    静态内部类使用外部类的实例变量直接调用外部类.实例变量(Outer.name)
    public class Outer {
    public static String name = "Tom";

    public static void hi() {
    System.out.println("xixi");
    }

    public static class Inner {
    public String name = "Jerry";

    public void say() {
    Outer.hi();
    System.out.println("Hello"+Outer.name);
    System.out.println("Hi!" + name);
    }
    }
    }

  3. 局部内部类(在外部类的内部声明的内部类成为局部内部类)
    public class Outer {
    public void outerMethod() {
    final String name = "tom";
    class Inner {
    private String name = "jack";
    System.out.println("innerMethod");
    }
    }

    }
    局部内部类创建在这个方法中,作用范围也在这个方法当中,因此在创建局部内部类的时候不需要添加public访问修饰符
    局部内部类不能使用访问修饰符类修饰,这个类的作用访问就在这个方法的内部。局部内部类的对象只能在外部类的方法中创建,并执行内部类的方法

    创建的方法只在这个方法的内部使用,这个时候可以使用局部内部类

    为什么要使用局部内部类?
    1.解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可用的
    2.在方法内部实现一个接口,并返回对其的引用

    局部内部类的方法需要引用外部类的方法的参数的时候,外部类方法的参数也必须是final类型的

    局部内部类使用局部变量时这个局部变量必须是final的
    当使用方法的参数的时候,方法的参数必须使用final来修饰

  4. 匿名局部内部类(只有方法体,没有类名的局部内部类成为局部内部类)
    example one:
    public interface Usb {
    public void run();
    }
    public Usb getUsb() {
    return new Usb(){
    @Override
    public void run() {
    System.out.println("runing...");
    }
    };
    }

    example two:
    public void method() {
    Object obj = new Object(){
    @Override
    public String toString() {
    return "hi";
    }
    };
    System.out.println(obj);
    }

    匿名局部内部类的简单框架
    public class A {
    public voie methodname() {
    类或接口 对象 = new 类或接口(){
    public type methodname() {

    }
    };
    }
    }
    新建一个类或者通过new一个接口来创建一个类,这个类没名字(不知道该起什么名字好),但是由方法和方法体。
    匿名局部内部类的原型
    public class A {
    public voie methodname() {
    类或接口 对象 = new 类或接口(){
    {
    //这个匿名局部内部类的构造
    }
    };
    }
    }
    创建一个匿名局部内部类的最简单方式,有匿名局部内部类,但是没有自定义方法

    example:
    Thread thread = new Thread(){
    run{
    System.out.println("thread start");
    }

    };

    tread.start();

    Object object = new Object(){
    toString(){
    System.out.println("hehe");
    }
    };

    System.out.println(object.toString());

    ArrayList<String> list = new ArrayList<String>{
    {
    add("a;sldfja");
    add("asdfasdf");
    }
    };
    System.out.println(list.size());

内部类的了解如上。

 

posted on 2015-09-10 23:12  shininguang  阅读(195)  评论(0编辑  收藏  举报