MySql & JDBC

一、什么是数据库?
     数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户能够经过SQL对数据库中的数据进行增长、修改、删除、及查询操做。
数据库系统类型(历史发展):
网状型数据库
层次型数据库
关系数据库 ---理论最成熟、应用最普遍
面向对象数据库
常见的数据库(软件):
MYSQL
Oracle
DB2
SQLServer
SyBase
SQLite
Java相关: MYSQL  Oracle
二、数据库和表
数据表示存储数据的逻辑单元,能够把数据表想象成有行和列组成的表格,其中每一行也被称为一条记录,每一列也被称为一个字段。(建表时:须要指定该表包含多少列,每列的数据的类型信息,无须指定包含多少行,数据库的行是动态改变的。特殊列被称为主键列。)
三、SQL语句
什么是SQL语句?
    Structured Query Language  结构化查询语言。关系数据库语言的国际标准。
SQL分类?
DDL:Data Definition Language 数控定义语言; 操做数据库对象的语句,包括建立create、删除drop、修改alter等(结构)
DML:Data Manipulation Language 数据操做语言,用来对数据库表的记录进行更新,包括插入insert 、 删除 delete 、 更新 update等 (数据)
DQL: Data Query Language  数据查询语言,用来查询数据库中表的记录。关键字:select,from where等
DCL:Data Control Language 数据控制语言;用来定义数据库的访问权限和安全级别,及建立用户:关键字 grant等
 
show databases;           查看当前实例下包含多少个数据库
create     database  if not exists  数据库名;    建立新的数据库
create database  数据库名 character set 字符集;
例子:create database web2 character set gbk;
查看某个数据库的定义的信息:show create  database  数据库名;
 
drop  database 数据库名;         删除指定数据库
 
use  数据库名;   切换数据库、
查看正在使用的数据库: select database();
 
show   tables;                查询数据库下包含多少数据表
desc  表名;            查看该表有多少列,每列的数据类型信息
 
DDL语句:
建立表:
create table 表名
     定义多个列定义;
);
修改表结构:
添加列:
alter table 表名
add (   能够有多个列定义; 字段名  类型  [约束] , );
 
约束:
NOT NULL : 非空
UNIQUE:惟一约束 
PRIMARY KEY : 主键   
(test_id  int  auto_increment  primary key); 自增加特性,不能指定该列值
FOREIGN KEY: 外键
CHECK:检查
 
修改列的类型、长度、约束:
alter table 表名   modify   要修改的字段名   类型(长度) 约束;
 
修改列的列名:
alter  table 表名
change  旧列名   新列名 类型(长度)  [约束];
 
删除表的列:
alter table 表名 drop 表列名;
 
修改表名:
atler table 表名
rename   to  新表名;
 
修改表字符集:
alter table 表名  
character  set  编码;
 
删除表:
drop  table 表名;
 
DML语法:
插入新数据       insert into
修改已有数据    update 
删除不须要的数据  deleter from 
 
insert:
语法:
insert into  表名  (列名1,列名2.....)values (值1,值2,....)......向表中插入某些列
insert into 表  values (值1,值2, 值3 ....)......向表中插入全部列
注意:
1.列名数与values后面的值得个数相等
2.列的顺序与插入的值得顺序一致
3.列名的类型与插入的值要一致
4.插入值得时候不能超过最大长度
5.值若是是字符串或者日期须要加引号‘’(通常都是单引号)
 
插入数据中文乱码问题解决办法:
方式一:[不建议]
直接修改数据库安装目录里面的 my.ini  文件的
第57行
default-character-set = utf8
 
方式二:
set  names  gbk;
 
update:
 
不带条件的:
update  表名  set  字段值= 值
它会将该列的全部记录都更改。
 
带条件的:
update  表名  set  字段值 = 值  where  条件
 
delete:
 
带条件的:
delete  from  表名  where   条件;
 
不带条件:
delete  from  表名;  //记录所有删除
 
面试题:
说说delete 与truncate的区别?
Delete删除的时候是一条一条的删除记录,它配合事务,能够将删除的数据找回。
Truncate删除,它是将整个表摧毁,而后再建立一张如出一辙的表。它删除的数据没法找回。
truncate  table  表名;
 
 
start transaction;  开启事务
delete from 表名;
select * from  表名;   //无数据
rollback;    //回滚下
select * from 表名;   //数据返回了
 
 
start  transaction;   开启事务
truncate  table  表名; 
select * from  表名;  //无数据
rollback;   //回滚下
select * from 表名  ;  仍是无数据
insert  into  表名  values (值1,值2,....)
注:transaction再添加数据uid重置,从1开始,而delete删除uid不会重置。(udi自增加的主键id,即定义以下:id int auto_increment primay key)。
 
四、DQL   SQL查询   注:最最重要,用到最多
语法:
select  列名,列名   from   数据源   where   条件;
 
 
#建立商品表
create table product(
pid int primary key auto_increment,
pname varchar(20),
price double,
pdate timestamp
)
#自动增加列:auto_increment,要求:1,必须整型(int) 2.必须是主键
insert into product values (null,'谭妮平',0.01,null);
insert into product values (null,'李士雪',38,null);
insert into product values (null,'左慈',-998,null);
insert into product values (null,'黄迎',99999,null);
insert into product values (null,'南国强',99998,null);
insert into product values (null,'士兵',1,null);
insert into product values (null,'李士兵',698,null);
 
1.3.3 简单查询
1.查询全部商品
select * from product;
2.查询商品名和商品价格
select pname, price  from product;
3.查询全部商品信息使用表别名
select * from product as p;
4.查询商品名,使用列别名
select pname as  p  from product;
5.去掉重复值(按照价格,需有数据)
select  distinct(price) from product;
6.将全部的商品的价格+10进行显示
select pname, price+10 from product;
 
1.3.4 条件查询
比较运算符
> 、 <    =   >=   <=   <> (不等于)
between  ... .and  ...    显示在某一区间的值(含头含尾)
in ()   显示在in列表中的值  
like  模糊查询,like语句中,%表明0个或多个任意字符,_表明一个字符
转义字符:MySQL使用反斜线(\)做为转义字符:
select * from student where sname like '\_%' (选出全部名字如下划线开头的学生)
is null   判断是否为空
逻辑运算符:
and  多个条件同时成立
or    多个条件任一成立
not  不成立 ,  例: where  not (salary > 100)
 
1.查询商品名称为"左慈"的商品信息
select * from product where pname = '左慈'
2.查询价格>60元的全部商品信息
select * from product where price > 60
3.查询商品名称含有"士"字的商品信息
select * from product where pname like '%士%'
4.查询商品id在(3,6,9)范围内的全部商品信息
select * from product where pid in (3,6,9);
 
1.3.5 排序(asc/desc)
1.查询全部的商品,按价格进行排序(升序、降序)
select * from product order by price asc;   //升序
select * from product order by price desc; //降序
2.查询名称有"士"的商品信息而且按照价格降序排序
select * from product where  pname like '%士%'  order by price desc;
 
1.3.6 聚合
经常使用聚合函数: sum()求和,  avg()平均,  max()最大值,min()最小值,count()计数
注意:聚合函数不统计null值
1.得到全部商品的价格的总和
select sum(price) from product;
2.得到全部商品的平均价格
select avg(price) from product;
3.得到全部商品的个数
select count(*) from product;
select count(distinct pname) from product;
 
1.3.7 分组
1.添加分类id (alter table product add cid varchar(32);)
2.初始化数据
update product set cid='1';
update product set cid='2' where pid in (5,6,7);
查询:
1.根据cid字段分组,分组后统计商品的个数。
select cid , count(*) from product group by cid;
2.根据cid分组,分组统计每组商品的平均价格,而且平均价格大于20000元。
select cid , avg(price)  from product group by cid having avg(price) >20000;
 
注意:若是须要对分组进行过滤,则应该使用having子句,having子句后面也是一个条件表达式,只有知足该条件表达式的分组才会被选出来。
 
查询总结:
select  *  |  字段 (通常放在"的"后面的内容都是要查询的字段)
from    表
where  查询条件
group by  分组字段
having     分组条件    分组后带有条件只能使用having
order by    排序字段  asc 、desc  (必须放在最后)
 
五、回顾JDBC
设置工做空间的编码:
windows->workspace->Text file encoding   -> other UTF-8。
建立JavaProject。
 
JDBC概述:
Java DataBase Connectivity: java 数据库了解。
一、JDBC是一种用于执行SQL语句的Java API;
二、JDBC能够为多种关系数据库提供统一访问入口;
三、JDBC由一组Java工具类和接口组成。
 
应用程序  <----> JDBC  <---->  MySQL驱动  <-----> MySQL
a、手动添加jar包到工程中,Bulid Path---> Add  --->   出现小奶瓶就添加成功!
 
Junit测试:
package com.scalpel.test;
 
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
 
public class TestUnit {
public static void main(String[] args) {
System.out.println("aa");
}
 
@Test
public void testJunit()
{
System.out.println("hello junit!");
}
 
@Before
public void testBefore()
{
System.out.println("before!");
}
 
@After
public void testAfter()
{
System.out.println("after");
}
}
 
注:运行只能点击testJunit() Run As   Junit Test.....
before!
hello junit!
after
 
JDBC开发步骤:
一、注册驱动
Class.forName("com.mysql.jdbc.Driver");
二、得到链接
Connection   conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root","12345678");
DriverManager.getConnection(url, username, password):三个参数分别是url:jdbc的地址(位置,网址) ,  username 用户名,  password  密码。
三、得到语句执行者
经过Connection对象建立Statement对象。
Statement stmt = conn.createStatement();
四、执行sql语句
stmt.executeUpdate(String sql语句)   执行DML和DDL语句。 insert update   delete
(注:返回受影响的行数!!!)
stmt.executeQuery(String sql语句) 执行DQL 语句  select 语句 。
(注:返回表明查询结果的ResultSet对象!!!)
ResultSet 实质是一个查询结果集,记录指针的初始位置是第一行以前。
(其余方法:privious()/first()/last()/beforeFist()等等)
ResultSet  rs = stmt.executeQuery(sql语句)
五、处理结果
rs.next();
rs.getXxx();
 
六、释放资源
栈(先进后出):
rs.close();
stmt.close();
con.close();
注:为何要释放资源?
 
JUnit Test:
 
package com.scalpel.test;
 
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
 
public class TestUnit {
public static void main(String[] args) {
System.out.println("aa");
}
 
@Test
public void testJunit()
{
System.out.println("hello junit!");
}
 
@Before
public void testBefore()
{
System.out.println("before!");
}
 
@After
public void testAfter()
{
System.out.println("after");
}
 
}
 
 
JDBC链接以及PreparedStatement执行SQL语句,防止SQL注入攻击问题
 
package com.scalpel.test;
 
import java.sql.*;
 
import org.junit.Test;
 
 
 
public class TestLogin {
 
@Test
public void testLogin()
{
try {
login1("ct", "123");  //注:若是login (“‘or true or’”,"");也是登陆成功
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
 
public void login( String username, String password ) throws ClassNotFoundException, SQLException
{
/**
* 用户登陆方法
* @author ctmc
*
*/
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取链接
Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root", "12345678");
//3.建立执行sql语句的对象
Statement stmt = conn.createStatement();
//4.书写一个sql语句
String sql = "select * from user where name = '" + username + "' and password = '" + password + "'" ;
//5.执行sql语句
ResultSet rs = stmt.executeQuery(sql);
//6.对结果集进行处理
if ( rs.next())
{
System.out.println("恭喜你,"+username+",登陆成功!");
System.out.println(sql);
}else
{
System.out.println("帐号或密码错误");
}
//7.关闭资源
if(rs != null)
{
rs.close();
}
if( stmt != null )
{
stmt.close();
}
if(conn != null )
{
conn.close();
}
}
 
public void login1 ( String username, String password ) throws ClassNotFoundException, SQLException
{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取链接
Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root", "12345678");
//3.编写sql语句
String sql = "select * from user where name = ? and password = ?";
//4.建立预处理对象
PreparedStatement pst = conn.prepareStatement(sql);
//5.设置参数(给占位符)
pst.setString(1, username);
pst.setString(2, password);
//6.执行查询操做
ResultSet rs = pst.executeQuery();
//7.对结果集进行处理
if ( rs.next())
{
System.out.println("恭喜你,"+username+",登陆成功!");
System.out.println(sql);
}else
{
System.out.println("帐号或密码错误");
}
//8.关闭资源
if(rs != null)
{
rs.close();
}
if( pst != null )
{
pst.close();
}
if(conn != null )
{
conn.close();
}
}
}
 
注:使用PreparedStatement 防止SQL注入攻击!!!?表明什么
 
 
六、Limit关键字进行查询操做(分页查询)
a、说出limit关键字两个参数的含义
(limit 2, 2) : 第一个2起始位置, 第二个2每页显示的数目
每页显示3条件记录,要查询第3页。
第一参数等于查询的页数减一乘以每页显示的数目,第二个参数是每页显示的数目
select * from product limit 6,3;
b、写出limit关键字查询数据SQL语句
 
总结:
一、说出JDBC的概念
二、说出JDBC的开发步骤
三、可以使用DriverManager类 (做用,加载驱动方法,获取链接方法)
四、可以使用Connection接口 (做用,获取接口的方法)
五、可以使用Statement接口
六、可以使用ResultSet接口
 
七、MySQL多表建立、查询
外键:
从表外键的值是对主表主键的引用。
从表外键类型,必须与主表主键类型一致。
声明外键约束:
alter table 从表 add [constraint] [外键名称]  foreign key (从表外键字段名)  references 主表 (主表的主键);
用于删除外键约束的,通常建议“_fk”结尾
alter  table 从表 drop  foreign key 外键名称
使用外键的目的:
保证数据完整性。
注意事项:
从表不能添加一条主表中不存在的记录。
主表不能删除,从表中已经引用的记录。
 
表与表之间的关系
a、一对多关系
一对多建表原则:在多的一方建立一个字段,字段做为外键指向少的一方的主键。
alter table 从表(product) add  foreign key (外键cno) references 主表(category)主键(cid)
 
b、多对多关系
多对多关系建表原则:须要建立第三张表,中间表中至少两个字段,这两个字段分别做为外键指向各自一方的主键。
alter table 从表(stu_course ) add foreign key(sno) references stu(sid);
alter table 从表(stu_course ) add foreign key(con) references course(cid);
 
c、一对一
两种建表原则:
外键惟一:主表的主键和从表的外键惟一,造成主外键关系,外键惟一unique。
外键是主键:主表的主键和从表的主键,造成主外键关系。
 
多表查询:
a、交叉链接查询(基本不用)
     select * from A,B;
b、内链接查询(使用关键字inner join   --inner能够省略)
隐式内链接:select * from A,B where 条件
显示内链接: select * from A  inner join B  on 条件 ;
c、外链接查询(使用的关键字 outer join --outer 能够省略)
左外链接:left outer join 
select * from A left outer join B on 条件;
右外链接:right outer join
select * from A right outer join B on 条件;
左外链接与右外链接的区别:
左外链接:左表所有及两个表的交集
右外链接:查询的是右边表的所有及两个表的交集。
内链接:查询两个表的交集。
全外链接:
d、子查询
子查询:一条select语句结果做为另外一条select语法一部分(查询条件,查询结果,表等)
 
八、JDBC工具类抽取方式
使用JDBC发送select语句完成单表【查询】操做。
//类:JDBCUtils_V1
 
package com.scalpel.jdbc;
/**
* 提供获取链接和释放资源的方法。
* @author ctmc
*
*/
import java.sql.*;
public class JDBCUtils_V1 {
    
    //链接Connection方法
    public static Connection getConnection()
    {
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root", "12345678");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }            
        return conn;        
    }
    
    //释放全部资源方法
    public static void release(Connection conn, PreparedStatement psmt, ResultSet rs)
    {
        if( rs!= null )
        {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( psmt != null )
        {
            try {
                psmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( conn != null )
        {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
    }
}
 
//测试类TestUtils   
package com.scalpel.test;
import java.sql.*;
import org.junit.Test;
import com.scalpel.jdbc.JDBCUtils_V1;
 
/**
 * 测试工具类
 * @author ctmc
 *
 */
public class TestUtils {
       /**
        * 根据id查询用户信息.
        */       
       @Test
       public void testFindUserById()
       {
             Connection conn = null;
             PreparedStatement pstmt = null;
             ResultSet rs = null;
             
             try {
             //1.获取链接
             conn = JDBCUtils_V1.getConnection();
             String sql = "select * from user where id = ? ";
             //3.获取执行SQL语句对象     
             pstmt =  conn.prepareStatement(sql);
             //4.设置参数
             pstmt.setInt(1, 2);
             //5.执行查询操做
             rs = pstmt.executeQuery();
             //6.处理结果集
             while ( rs.next() )
             {
                    System.out.println(rs.getString("name")+"-----"+rs.getString("password"));
             }
             
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }finally {
                    //7.释放资源
                    JDBCUtils_V1.release(conn, pstmt, rs);
             }
       }
}    
 
注意:一、PreparedStatement的用法。二、释放资源为何要放在finally中,能不能放在try中?    
 
PreparedStatement的用法:
数据库的操做过程当中,PreparedStatement 对象是一个很不起眼可是记为重要的接口对象,它继承 于Statement,并与之在两方面有所不一样:
1)PreparedStatement 实例包含已编译的 SQL 语句。这就是使语句“准备好”。包含于 PreparedStatement 对象中的 SQL 语句可具备一个或多个 IN 参数。IN参数的值在 SQL 语句建立时未被指定。相反的,该语句为每一个 IN 参数保留一个问号(“?”)做为占位符。每一个问号的值必须在该语句执行以前,经过适当的setXXX 方法来提供。
2)因为 PreparedStatement 对象已预编译过,因此其执行速度要快于 Statement 对象。所以,屡次执行的 SQL 语句常常建立为 PreparedStatement 对象,以提升效率。
例如:SQL语句为:String sql = select * from  user  where  id = ?(整型)  and  name = ?(字符串);
在pstmt.setXXX设置是,第一个参数要整型,第二个参数为字符串类型。
在ResultSet 得到结果。
rs.getString(1)  或者 rs.getString("name");获得的结果同样 (数据库该表第一位为name)!
 
九、使用properties配置文件
    开发中得到链接的4个参数(驱动、URL、用户名、密码)一般都保存在配置文件中,方便后期维护,程序若是须要更换数据库,只须要修改配置文件便可。
    一般状况下,咱们习惯使用properties文件,此文件咱们将作以下要求:
    a、文件位置:任意,建议放在src下(非web程序)
    b、文件名称:任意,扩展名为properties
    c、文件内容:一行一组数据,格式是:“key=value”(不要有空格)
     !key命名自定义,若是是多个单词,习惯使用点分隔,例如:jdbc.driver
     @value值不支持中文,若是须要使用非英文字符,将进行unicode转换
 
建立properties配置文件(注:不要有空格)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/web
username=root
password=12345678
加载配置文件----ResourceBundle对象
package com.scalpel.jdbc;
/**
* 提供获取链接和释放资源的方法。
* @author ctmc
*
*/
import java.sql.*;
import java.util.ResourceBundle;
public class JDBCUtils_V2 {
    
     private static String  driver;
     private static String  url;
     private static String  username;
     private static String  password;
     /**
      * 静态代码块加载配置文件信息。
      * */
    static
    {
        ResourceBundle rb = ResourceBundle.getBundle("db");
        driver = rb.getString("driver");
        url = rb.getString("url");
        username = rb.getString("username");
        password = rb.getString("password");
    }
    
    //链接Connection方法
    public static Connection getConnection()
    {
        Connection conn = null;
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url,username,password);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }            
        return conn;        
    }
    
    //释放全部资源方法
    public static void release(Connection conn, PreparedStatement psmt, ResultSet rs)
    {
        if( rs!= null )
        {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( psmt != null )
        {
            try {
                psmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( conn != null )
        {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }       
    }      
}    
 
添加表信息:
       /**
        * 添加用户信息方法
        */
       @Test
       public void testAdd()
       {
             Connection conn = null;
             PreparedStatement pstmt = null;
             try {
                    //1.获取链接
                    conn = JDBCUtils_V2.getConnection();
                    //2.编写SQL语句
                    String sql = "insert into user values(?,?,null)";
                    //3.获取执行sql语句对象
                    pstmt = conn.prepareStatement(sql);
                    //4.设置参数
                    pstmt.setString(1,"zll");
                    pstmt.setString(2,"zll");
                    //5.执行插入操做,返回一个值是否添加成功。
                    int row = pstmt.executeUpdate();
                    if ( row > 0 )
                    {
                           System.out.println("添加信息成功!");
                    }
                    else
                    {
                           System.out.println("添加失败!");
                    }
                    
             } catch (Exception e) {
                    throw new RuntimeException(e);
             }finally {
                    //6.释放资源
                    JDBCUtils_V2.release(conn, pstmt, null);
                    //注:无参数设置为null
             }             
       }
 
根据ID删除用户信息:
配置文件加载方法改变:
package com.scalpel.jdbc;
/**
* 提供获取链接和释放资源的方法。
* @author ctmc
*
*/
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
import java.util.ResourceBundle;
public class JDBCUtils_V3 {
    
     private static String  driver;
     private static String  url;
     private static String  username;
     private static String  password;
     /**
      * 静态代码块加载配置文件信息。
      * */
    static
    {
        try {
            //1.经过当前类获取类加载器
            ClassLoader cl = JDBCUtils_V3.class.getClassLoader();
            //2.经过类加载器的方法得到一个输入流、
            InputStream is = cl.getResourceAsStream("db.properties");
            //3.建立一个properties对象
            Properties props = new Properties();
            //4.加载输入流        
            props.load(is);
            //5.获取相关参数的值
            driver = props.getProperty("driver");
            url = props.getProperty("url");
            username = props.getProperty("username");
            password = props.getProperty("password");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
         is.close();   
         }
    }
    
    //链接Connection方法
    public static Connection getConnection()
    {
        Connection conn = null;
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url,username,password);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }            
        return conn;        
    }
    
    //释放全部资源方法
    public static void release(Connection conn, PreparedStatement psmt, ResultSet rs)
    {
        if( rs!= null )
        {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( psmt != null )
        {
            try {
                psmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( conn != null )
        {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }        
    }      
}    
 
注:实现全部资源释放的方法,上例中使用多个try-catch块,将资源释放,容易理解。可是多个try-catch并列,catch块中不能抛出异常,不然将阻止程序的继续执行。
应该修改成:try-catch-finally嵌套,资源释放时若是出错,将通知调用者,还能够继续释放其余资源。
/**
        * 根据id删除信息的方法
        */
       @Test
       public void testDleteById()
       {
             Connection conn = null;
             PreparedStatement pstmt = null;
             try {
                    //1.获取链接
                    conn = JDBCUtils_V3.getConnection();
                    //2.编写SQL语句
                    String sql = "delete from user where id = ?";
                    //3.获取执行sql语句对象
                    pstmt = conn.prepareStatement(sql);
                    //4.设置参数
                    pstmt.setInt(1,3);               
                    //5.执行插入操做
                    int row = pstmt.executeUpdate();
                    if ( row > 0 )
                    {
                           System.out.println("删除信息成功!");
                    }
                    else
                    {
                           System.out.println("删除失败!");
                    }
                    
             } catch (Exception e) {
                    throw new RuntimeException(e);
             }finally {
                    //6.释放资源
                    JDBCUtils_V2.release(conn, pstmt, null);
             }  
       }
 
十、Java项目读取properties文件的几种方法
1、项目中常常会须要读取配置文件(properties文件),所以读取方法总结以下: 
一、经过java.util.Properties读取 
Java代码 
  1. Properties p=new Properties();  
  2. //p须要InputStream对象进行读取文件,而获取InputStream有多种方法:  
  3. //一、经过绝对路径:InputStream is=new FileInputStream(filePath);  
  4. //二、经过Class.getResourceAsStream(path);  
  5. //三、经过ClassLoader.getResourceAsStream(path);   经过本身的类加载最妥当!?why?
  6. p.load(InputStream is);  
  7. is.close();  
  8. p.getString(String(key))  
二、经过java.util.ResourceBundle读取 
Java代码  
  1. ResourceBundle rb=ResourceBundle.getBundle(packageName);  
  2. rb.getString(String key);  
 
十一、JDBC 链接池&DBUtils
链接池:解决资源浪费,提供代码性能。
本小节目标:
使用DBCP,C3P0链接池完成基本数据库的操做。
使用DBUtils完成CRUD的操做。
 
数据库链接池的解决方案是:
当应用程序启动时,系统主动创建足够的数据库链接,并将这些链接组成一个链接池。每次应用程序请求数据库链接时,无须从新打开链接,而是从链接池中取出已有的链接使用,使用完后再也不关闭数据库链接,而是直接将链接归还给链接池。经过使用链接池,将大大提升程序的运行效率。
 
数据库链接池是Connection 对象的工程。数据库链接池的经常使用参数以下。
a、数据库的初始链接数
b、链接池的最大链接数
c、链接池的最小链接数
d、链接池每次增长的容量
 
公共接口:javax.sql.DataSource。
常见的链接池:DBCP 、 C3P0 (主要)
 
1、自定义链接池
一、建立链接池实现(数据源),并实现接口javax.sql.DataSource。由于咱们只使用该接口中getConnection()方法。
二、提供一个集合,用于存放链接,由于移除、添加操做过多,因此选择LinkedList
 
代码例子:
提供获取链接和释放资源的方法仍是使用JDBCUtils_V3.java
package com.scalpel.DataSource;
 
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.logging.Logger;
 
import javax.sql.DataSource;
import javax.sql.PooledConnection;
 
import com.scalpel.jdbc.JDBCUtils_V3;
 
public class MyDataSource implements DataSource {
       
       //1.建立一个容器,用于存储Connection对象
       private static LinkedList<Connection> pool = new LinkedList<Connection>();
       
       //2.建立5个链接放到容器中去
       static
       {
             for (int i = 0; i < 5; i++)
             {
                    Connection conn = JDBCUtils_V3.getConnection();
                    pool.add(conn);                  
             }
       }
       /**
        * 重写获取一个链接的方法
        */
       @Override
       public Connection getConnection() throws SQLException {
             Connection conn = null;
             //3.使用前先判断
             if( pool.size() == 0 )
             {
                    //4.池子里面没有,咱们在建立一些
                    for (int i = 0; i < 5; i++)
                    {
                           conn = JDBCUtils_V3.getConnection();
                           pool.add(conn);                  
                    }                   
             }
             //5.从池子里面获取一个链接对象Connection,list的remove()方法
             //删除并返回index索引处的元素   
             conn  = pool.remove(0);          
             return conn;
       }
       
       /**
        * 归还链接对象到链接池中去
        */
       public void backToPool ( Connection conn )
       {
             //链接用完后,再归还到链接池中,直接插入到list集合中。
             pool.add(conn);            
       }
       
 
       @Override
       public PrintWriter getLogWriter() throws SQLException {
             // TODO Auto-generated method stub
             return null;
       }
 
       @Override
       public int getLoginTimeout() throws SQLException {
             // TODO Auto-generated method stub
             return 0;
       }
 
       @Override
       public Logger getParentLogger() throws SQLFeatureNotSupportedException {
             // TODO Auto-generated method stub
             return null;
       }
 
       @Override
       public void setLogWriter(PrintWriter out) throws SQLException {
             // TODO Auto-generated method stub
             
       }
 
       @Override
       public void setLoginTimeout(int seconds) throws SQLException {
             // TODO Auto-generated method stub
             
       }
 
       @Override
       public boolean isWrapperFor(Class<?> arg0) throws SQLException {
             // TODO Auto-generated method stub
             return false;
       }
 
       @Override
       public <T> T unwrap(Class<T> arg0) throws SQLException {
             // TODO Auto-generated method stub
             return null;
       }
 
       
 
       @Override
       public Connection getConnection(String username, String password) throws SQLException {
             // TODO Auto-generated method stub
             return null;
       } 
}
 
测试方法:
package com.scalpel.jdbc.test;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
 
import org.junit.Test;
 
import com.scalpel.DataSource.MyDataSource;
 
public class TestMyDataSource {
       
       @Test
       public void testAddUser()
       {
             Connection conn = null;
             PreparedStatement pstmt = null;
             //建立自定义链接池对象
             MyDataSource dataSource = new MyDataSource();
             try
             {
                    //2.从池子中获取链接
                    conn = dataSource.getConnection();
                    String sql = "insert into user values(?,?,null)";
                    pstmt = conn.prepareStatement(sql);
                    pstmt.setString(1, "xixi");
                    pstmt.setString(2, "456");
                    int rows = pstmt.executeUpdate();
                    if ( rows > 0 )
                    {
                           System.out.println("添加成功!");
                    }
                    else
                    {
                           System.out.println("添加失败!");
                    }                   
             } catch (Exception e) {
                    throw new RuntimeException();
             }finally {
                    dataSource.backToPool(conn);
             }
       }
}
 
注:若是插入数据为中文,会出现数据库中乱码显示?
怎样解决这个问题?
 
自定义链接池代码实现改进(加强close方法):
    自定义链接池中存在的严重问题,用户调用getConnection()得到链接后,必须使用release()方法进行链接的归还,若是用户调用conn.close()将链接真正的释放,链接池中将出现无链接能够。
 
方法加强的办法:
a、继承,子类继承父类,将父类的方法进行复写,从而进行加强。
    使用前提:必须有父类,且存在继承关系。
b、装饰者设计模式,此设计模式专门用于加强方法。
    使用前提:必须有接口
    缺点:须要将接口的全部方法都实现
c、动态代理:在运行时动态的建立代理类,完成加强操做。与装饰者类似
    使用前提:必须有接口
    难点:须要反射技术
d、字节码加强,运行时建立目标类子类,从而进行加强
    常见第三方框架:cglib 、javassist等。
 
C3P0链接池:
    C3P0开源免费的链接池!目前使用它的开源项目有:Spring 、 Hibernate等。使用第三方工具须要导入jar包,C3P0使用时还须要添加配置文件c3p0-config.xml(固定)
 
在增长、删除、修改等操做中有不少相同的代码,只有少部分的不一样。对于那些不一样的地方,咱们使用传参的方法来解决!!!
    若是只使用JDBC进行开发,咱们会发现冗余代码过多,为了简化JDBC开发,本案例咱们讲采用apache commons组件一个成员:DBUtils。
    DBUtils就是JDBC的简化开发工具包。须要使用技术:链接池(得到链接),SQL语句都没有少。
 
JavaBean组件:
JavaBean就是一个类,在开发中经常使用语封装数据。具备以下特性:
a、须要实现接口:java.io.Serializable  (一般省略)
b、提供私有字段:private 类型,字段名;
c、提供getter、setter方法;(空白处,source->setter  getter)
d、提供无参构造
 
放在com.scalpel.domain包中(构造方法)
package com.scalpel.domain;
 
public class User {
       private int id;
       private String password;
       private String name;
       
       
       public String getName() {
             return name;
       }
       public void setName(String name) {
             this.name = name;
       }
       public  User()
       {            
       }
       public int getId() {
             return id;
       }
       public void setId(int id) {
             this.id = id;
       }      
       
       public String getPassword() {
             return password;
       }
       public void setPassword(String password) {
             this.password = password;
       }      
}
 
注:JavaBean的私有字段名,必须与数据库中的列名同样!!!
不然查询出来就是null。必须同样。
 
DBUtils概述:
DBUtils是java编程中的数据库操做实用工具,小巧简单实用。
DBUtils封装了对JDBC的操做,简化了JDBC操做,能够少些代码。
DBUtils三个核心功能介绍:
a、QueryRunner中提供对sql语句操做的API
核心类:
QueryRunner( DataSource ds),链接池
update(String sql, Object ....params),执行更新数据
query(String sql, ResultSetHandler<t> rsh, Object ....params),执行查询
b、ResultSetHandler接口,用于定义select操做后,怎样封装结果集
BeanHandler: 将结果集中第一条记录封装到一个指定的javaBean中。
BeanListHandler:将结果集中每一条记录封装到指定的javaBean中,将这些javaBean再封装到集合中。
ScalarHandler
c、DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法
 
c3p0-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
 
  <default-config>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
       <property name="jdbcUrl">jdbc:mysql:///web</property>
       <property name="user">root</property>
       <property name="password">12345678</property>
       <property name="initialPoolSize">5</property>
       <property name="maxPoolSize">20</property>
  </default-config>
 
  <named-config name="scalpel">
    <property name="driverClass">com.mysql.jdbc.Driver</property>
       <property name="jdbcUrl">jdbc:mysql:///web</property>
       <property name="user">root</property>
       <property name="password">12345678</property>
  </named-config>
</c3p0-config>
 
C3P0Utils.java
package com.scalpel.jdbc.utils;
 
import java.sql.Connection;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
 
public class C3P0Utils {
       
       private static ComboPooledDataSource  dataSource =
                           new  ComboPooledDataSource("scalpel");  
       
       public static DataSource getDataSource()
       {
             return dataSource;         
       }
       
       public static Connection getConnection()
       {
             try {
                    return dataSource.getConnection();             
                    
             } catch (Exception e) {
                    throw new RuntimeException();
             }
       }      
 
}
 
TestDBUtils.java
package com.scalpel.jdbc.test;
 
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;
import com.scalpel.jdbc.utils.C3P0Utils;
 
/**
 * 测试DBUtils工具类
 * @author ctmc
 *
 */
public class TestDBUtils {
       
       @Test
       public   void testDeleteUserById()
       {
             try {
             //1.建立核心类QueryRunner
             QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
             //2.编写sql语句
             String sql = "delete from user where id = ?";
             //3.为占位符设置值
             Object[] params = {7};
             //4.执行添加操做           
             int rows =  qr.update(sql,params);
             if ( rows > 0 )
             {
                    System.out.println("删除成功");
             }
             else
             {
                    System.out.println("删除失败");
             }
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }      
       
       /**
        * 添加用户
        */
       @Test
       public void testAddUser()
       {
             try {
             //1.建立核心类QueryRunner
             QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
             //2.编写sql语句
             String sql = "insert into user values(?,?,null)";
             //3.为占位符设置值
             Object[] params = {"xizll","789"};
             //4.执行添加操做           
             int rows =  qr.update(sql,params);
             if ( rows > 0 )
             {
                    System.out.println("添加成功");
             }
             else
             {
                    System.out.println("添加失败");
             }
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }
 
}
 
查询select代码:
package com.scalpel.jdbc.test;
 
import java.sql.SQLException;
import java.util.List;
 
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;
 
import com.scalpel.domain.User;
import com.scalpel.jdbc.utils.C3P0Utils;
 
public class TestDBUtilsSelect {
       
       /*
        * 查询全部用户个数
        */
       @Test
       public void testUserNum()
       {
             try {
             QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
             String sql = "select count(*) from user";                   
             long num =  (long) qr.query(sql, new ScalarHandler());
             System.out.println(num);
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }            
       }      
       
       /*
        * 根据id查询用户
        */
       @Test
       public void testQueryUserById()
       {
             try {
             //1.获取核心类queryRunner
             QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
             //2.编写sql语句
             String sql = "select * from user where id = ?";
             //3.为占位符设置值
             Object[] params = {9};
             //4.执行查询操做     
             User user = qr.query(sql, new BeanHandler<User>(User.class), params);
             //5.对结果集单个进行输出
             System.out.println(user.getName()+" : " + user.getPassword());                           
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }
       
       /**
        * 查询全部用户
        * */
       @Test
       public void testQueryAll()
       {
             try {
             //1.获取核心类queryRunner
             QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
             //2.编写sql语句
             String sql = "select * from user";
             //3.执行查询操做           
             List<User> users = qr.query(sql, new BeanListHandler<User>(User.class));
             //4.对结果集集合进行遍历
             for (User  user : users)
             {
                    System.out.println(user.getName()+" : " + user.getPassword());                    
             }            
             } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
             }
       }
 
}
相关文章
相关标签/搜索