MySql & JDBC

1、什么是数据库?

数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以通过SQL对数据库中的数据进行增加、修改、删除、及查询操作。

数据库系统类型(历史发展):

网状型数据库

层次型数据库

关系数据库 ---理论最成熟、应用最广泛

面向对象数据库

常见的数据库(软件):

MYSQL

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();

}

}

}

时间: 2025-01-04 09:27:06

MySql & JDBC的相关文章

java链接MySQL数据库时使用com.mysql.jdbc.Connection的包会出红线问题

package com.swift; //这里导入的包是java.sql.Connection而不是com.mysql.jdbc.Connection import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class TestJDBC { public static void main(String[] args) { try { Class.forName(

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxError Exception

1.错误描述 com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxError Exception:You have an error in your SQL syntax check the manual that corresponds to your MySQL server version for the right syntax to use near 'notnull,user_name varchar(255) )' at line 1 2.错误原因

com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1169 &gt; 1024)

### Cause: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (1169 > 1024). You can change this value on the server by setting the max_allowed_packet' variable. ; SQL []; Packet for query is too large (1169 > 1024). You can change

WEB中的java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

必须把mysql-connector-java-5.1.7-bin.jar导入到tomcat的lib目录下面! 在java项目中,只需要引入mysql-connector-java-5.1.7-bin.jar就可以运行java项目. 在web项目中,当Class.forName("com.mysql.jdbc.Driver");时eclipse是不会去查找字符串,不会去查找驱动的.所以只需要把mysql-connector-java-5.1.7-bin.jar拷贝到tomcat下lib

开发中出现的异常com.mysql.jdbc.CommunicationsException

web开发遇到的异常: com.mysql.jdbc.CommunicationsException:The last packet successfully received from the server was58129 seconds ago.Thelast packet sent successfully to the server was 58129 seconds ago, which islonger than the server configured value of 'wa

错误:“Cannot load JDBC driver class &#39;com.mysql.jdbc.Driver”的解决方法

"Cannot load JDBC driver class 'com.mysql.jdbc.Driver " 表示没有JDBC连接MySql的驱动包,因此需要手动添加驱动包到WEB-INF目录下的lib目录中. 解决方法: 从网上下载mysql-connector-java.jar,将其放到"D:\workspace\my-web\src\main\webapp\WEB-INF\lib"目录下,即可解决上述问题. 错误:"Cannot load JDBC

ClassNotFoundExceptioncom.mysql.jdbc.Driver

调试3M网站项目时出现错误提示:ClassNotFoundExceptioncom.mysql.jdbc.Driver 原因分析:项目中缺少mysql-connector-java-5.1.22-bin.jar包 解决办法: ①右键工程名->New->Folder,新建文件夹lib,右键lib文件夹->Import导入mysql-connector-java-5.1.22-bin.jar ②选中jar包右击--->BuildPath--->Add To Build Path,

mysql jdbc的使用

先创建一个库petdb,  再创建一个表pettable,在里面加入数据.使用jdbc读出. import java.sql.*; /** * Created by chuiyuan on 2/6/16. */ public class mysql { /** * JDBC driver name and database URL */ static final String DB_NAME="petdb"; static final String TABLE_NAME="p

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL

1.错误描述 org.hibernate.exception.SQLGrammarException: error executing work at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:80) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(