MySql & JDBC

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySql & JDBC相关的知识,希望对你有一定的参考价值。

1、什么是数据库?
     数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以通过SQL对数据库中的数据进行增加、修改、删除、及查询操作。
数据库系统类型(历史发展):
网状型数据库
层次型数据库
关系数据库 ---理论最成熟、应用最广泛
面向对象数据库
常见的数据库(软件):
Oracle
DB2
SQLServer
SyBase
SQLite
Java相关: MYSQL  Oracle
2、数据库和表
数据表示存储数据的逻辑单元,可以把数据表想象成有行和列组成的表格,其中每一行也被称为一条记录,每一列也被称为一个字段。(建表时:需要指定该表包含多少列,每列的数据的类型信息,无须指定包含多少行,数据库的行是动态改变的。特殊列被称为主键列。)
3、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)。
 
4、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  (必须放在最后)
 
5、回顾JDBC
设置工作空间的编码:
windows->workspace->Text file encoding   -> other UTF-8。
创建JavaProject。
 
JDBC概述:
Java DataBase Connectivity: java 数据库了解。
1、JDBC是一种用于执行SQL语句的Java API;
2、JDBC可以为多种关系数据库提供统一访问入口;
3、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开发步骤:
1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
2、获得连接
Connection   conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root","12345678");
DriverManager.getConnection(url, username, password):三个参数分别是url:jdbc的地址(位置,网址) ,  username 用户名,  password  密码。
3、获得语句执行者
通过Connection对象创建Statement对象。
Statement stmt = conn.createStatement();
4、执行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语句)
5、处理结果
rs.next();
rs.getXxx();
 
6、释放资源
栈(先进后出):
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注入攻击!!!?代表什么
 
 
6、Limit关键字进行查询操作(分页查询)
a、说出limit关键字两个参数的含义
(limit 2, 2) : 第一个2起始位置, 第二个2每页显示的数目
每页显示3条件记录,要查询第3页。
第一参数等于查询的页数减一乘以每页显示的数目,第二个参数是每页显示的数目
select * from product limit 6,3;
b、写出limit关键字查询数据SQL语句
 
总结:
1、说出JDBC的概念
2、说出JDBC的开发步骤
3、能够使用DriverManager类 (作用,加载驱动方法,获取连接方法)
4、能够使用Connection接口 (作用,获取接口的方法)
5、能够使用Statement接口
6、能够使用ResultSet接口
 
7、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语法一部分(查询条件,查询结果,表等)
 
8、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);
             }
       }
}    
 
注意:1、PreparedStatement的用法。2、释放资源为什么要放在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)!
 
9、使用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);
             }  
       }
 
10、Java项目读取properties文件的几种方法
一、项目中经常会需要读取配置文件(properties文件),因此读取方法总结如下: 
1、通过java.util.Properties读取 
Java代码 
  1. Properties p=new Properties();  
  2. //p需要InputStream对象进行读取文件,而获取InputStream有多种方法:  
  3. //1、通过绝对路径:InputStream is=new FileInputStream(filePath);  
  4. //2、通过Class.getResourceAsStream(path);  
  5. //3、通过ClassLoader.getResourceAsStream(path);   通过自己的类加载最稳当!?why?
  6. p.load(InputStream is);  
  7. is.close();  
  8. p.getString(String(key))  
2、通过java.util.ResourceBundle读取 
Java代码  
  1. ResourceBundle rb=ResourceBundle.getBundle(packageName);  
  2. rb.getString(String key);  
 
11、JDBC 连接池&DBUtils
连接池:解决资源浪费,提供代码性能。
本小节目标:
使用DBCP,C3P0连接池完成基本数据库的操作。
使用DBUtils完成CRUD的操作。
 
数据库连接池的解决方案是:
当应用程序启动时,系统主动建立足够的数据库连接,并将这些连接组成一个连接池。每次应用程序请求数据库连接时,无须重新打开连接,而是从连接池中取出已有的连接使用,使用完后不再关闭数据库连接,而是直接将连接归还给连接池。通过使用连接池,将大大提高程序的运行效率。
 
数据库连接池是Connection 对象的工程。数据库连接池的常用参数如下。
a、数据库的初始连接数
b、连接池的最大连接数
c、连接池的最小连接数
d、连接池每次增加的容量
 
公共接口:javax.sql.DataSource。
常见的连接池:DBCP 、 C3P0 (主要)
 
一、自定义连接池
1、创建连接池实现(数据源),并实现接口javax.sql.DataSource。因为我们只使用该接口中getConnection()方法。
2、提供一个集合,用于存放连接,因为移除、添加操作过多,所以选择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();
             }
       }
 
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

以上是关于MySql & JDBC的主要内容,如果未能解决你的问题,请参考以下文章

干货jdbcmysql批量删除方法in

jdbc mysql执行更新不起作用

JDBC连接MySQL数据库

找不到适合 jdbc mysql 的驱动程序?

Eclipse连接MySQL数据库教程!

部署后找不到 jdbc mysql 驱动程序