前提下载:mysql-connector-java,工程下建立lib文件夹将压缩包放入,右键压缩包build path 把jar包导入
这个压缩包用于java和mysql的连接(mysql的JDBC)
建立简单JDBC的连接
1.数据库的driver向java的DriverManager注册
2.java的DriverManager连接数据库(上一步的意义就是让这步知道应该连接哪一个数据库)
3.这时候数据库和java连接上了,但是如果想要传输数据你必须要还要在连接上获得传输器
String driver="com.mysql.jdbc.Driver";//驱动路径(Driver类的全类名)
String url="jdbc:mysql://localhost:3306/数据库名";//数据库地址
String user="root";//访问数据库的用户名
String password="123456";//用户密码
try {
//1、加载驱动
Class.forName(driver); //实例化Driver类
//对于系统说并不确定用的是哪一个数据库,java提供一个大管家,用于管理当前使用的是哪个数据库的连接,这个大管家就是DriverManager。想要和某个数据库相连,就要向这个数据库注册一下,告诉它想要和那个数据库相连。实例化过程自动向DriverManager注册使用哪个driver,不需要显示调用DriverManager.registerDriver方法(将数据库的Driver向java的DriverManager注册,注册后java和mysql就处于准备连接阶段)
//2、连接数据库
Connection con = DriverManager.getConnection(url, user, password);
if(!con.isClosed()){//判断数据库是否链接成功
System.out.println("已成功链接数据库!");
//3、建立传输器(Statement对象)
Statement st = con.createStatement();
//4、执行sql语句
String sql="select *from user";//查询user表的所有信息
ResultSet rs = st.executeQuery(sql);//查询之后返回结果集
//ResultSet用来存储从数据库中查询的结果
//5、打印出结果
while(rs.next()){
//next()方法,类似一个游标,从0数据开始,每调用一次就指向rs的下一个数据,也就是表里的下一行 System.out.println(rs.getString("Id")+"\t"+rs.getString("name")+"\t"+rs.getString("password"));
//rs.getString("Id")表示将rs里的id字段的数据当做字符串取出,与实际字段数据类型无关
也可以使用rs.getString(1)表示获取第一个字段值
}
}
rs.close();//关闭资源
con.close();//关闭数据库
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
executeQuery(sql) 用于执行select语句
executeUpdate(sql)用于执行select以外语句 (返回值>0修改成功 <0插入失败)
解决中文乱码问题
若想往数据库里插入汉字首先保证数据库和eclipse的编码一致 然后 在url尾部加上 ?characterEncoding=utf8 并且设置编辑器的编码为utf-8(有时候需要专门更改某个字段的编码)
注:实际开发过程应该先检查能否插入汉字(必须统一开发工具版本!!)
以上是一个初级的JDBC程序,若完善,需要改成以下
2.获取JDBC的连接和关闭连接的工具类(通过配置文件进行连接)
配置文件存在src目录下,因为ecplise会把src下目录的文件当做是当前目录
public class JDBCTools {
private static String driver;
private static String url;
private static String username;
private static String password;
private static Properties prop=new Properties(); //类似Map集合
static{ //静态初始化块
InputStream in=null; //建立一个输入流
try {
in=JDBCTools.class.getClassLoader().getResourceAsStream("db.properties");
/*getResourceAsStream()是用来获取文件中资源
JDBCTools.class.getClassLoader()代码的意思是
先得到JDBCtools的Class对象,然后得到这个类的加载器,
最后用这个加载器去加载需要的资源文件
其实也可以使用FileInputStream读取文件
*/
prop.load(in); //将输入流装在到Properties集合类中
//得到key对应的value
driver=prop.getProperty("jdbc.driver");
url=prop.getProperty("jdbc.url");
username=prop.getProperty("jdbc.username");
password=prop.getProperty("jdbc.password");
Class.forName(driver); //加载驱动
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection getConnection(){ //获取连接的方法
Connection conn=null;
try {
conn=DriverManager.getConnection(url,username,password);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
public static void closeConnection(Connection conn,Statement stmt,ResultSet rs){
try { //关闭连接的方法
if(rs != null)
rs.close();
if(stmt != null)
stmt.close();
if(conn != null)
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.PreparedStatement(实际开发用的)
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Demo1 {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
String url="jdbc:mysql://localhost:3306/sunhao?characterEncoding=utf8";
//解决中文乱码的问题
String username="root";
String password="123456";
String driver="com.mysql.jdbc.Driver";
try {
Class.forName(driver);
conn=DriverManager.getConnection(url,username,password);
String sql="select *from emp where empno=?";
ps=conn.prepareStatement(sql); //预编译
ps.setInt(1,7369); //赋参数,为第一个问号位置赋值7369
rs=ps.executeQuery(); //执行sql
if(rs.next()){
System.out.println(rs.getString("ename"));
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4.利用preparedStatement实现登陆注册
public class UserDaoImpl {
public User login(User u){ //因为一般登陆有后续操作所以如果数据库中有这么个人,就返回他
User u1=null;
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
conn=JDBCTools.getConnection();
String sql="select * from t_user where username=? and password=?";
try {
ps=conn.prepareStatement(sql);
ps.setString(1, u.getUsername());
ps.setString(2, u.getPassword());
rs=ps.executeQuery();
if(rs.next()){
u1=new User(rs.getString("username"),rs.getString("password"));
return u1;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return u;
}
public void register(User u) throws SQLException{
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
conn=JDBCTools.getConnection();
String sql="insert into t_user values(?,?)";
ps=conn.prepareStatement(sql);
ps.setString(1, u.getPassword());
ps.setString(2, u.getPassword());
int falg=ps.executeUpdate();
if(falg>0){
System.out.println("插入成功");
}else{
System.out.println("插入失败");
}
}
}
注意模糊查找的时候不能在预编译的sql语句里使用%?%而应该是 ? 在参数里为?赋值为模糊查找%张 %
模拟DButils工具包的方法
1.建立可以插入可变参数的数据增删改方法。update(String sql,Object...obj)
public class UTl {
public void update(String sql,Object...obj) throws SQLException{
Connection conn=null; //可变参数的obj的长度就是sql里占位符个数,用于替换占位符
PreparedStatement ps=null;
conn=JDBCTools.getConnection();
ps=conn.prepareStatement(sql); //sql是具有占位符的语句
for(int i=0;i0){
System.out.println("插入成功");
}
}
2.建立一个完成查询的工具方法,
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.sql.ResultSetMetaData;
import com.qianfeng.demo1.JDBCTools;
public class DDD {
/*为什么查询不用和增删改类似的方法?
因为增删改的时候,是往数据库里操作,
而查是将数据库里的内容存在对象里,
这时你不知道表和类中到底有哪些属性,所以需要调用方法获取数据库的字段和值
然后将字段值存到对象的对应属性里
在此过程就需要 有获得数据库字段的方法,
而此时返回值应该是存完值后的类对象,但是由于是万能查找,
你不知道你查找的数据库应该返回的是什么类,返回值就设置成了泛型
传递一个泛型类的反射的原因是,普通类是无法给一个不确定的字段进行赋值的
而类的反射却可以给不确定的私有属性进行赋值
(获取数据库的字段名,然后调用反射的cls.getDeclaredField(fileName);方法就可以得到类中属性的名字,再通过field.set(obj, fileValue);就可以把值存给对应属性了)
*/
/*1.获取链接
2.获取PreparedStatement
3.获取结果集
4.获取结果集元数据(字段)
5.把数据存入map集合
6.遍历map集合存入对象(其实此时完全可以直接把字段—字段值存入对象,多次一举,只是为了易于理解)
*/
public T find(Class cls,String sql,Object...obj) throws SQLException, InstantiationException, IllegalAccessException{
/*第一个参数是一个反射对象,泛型表示的是这个泛型对象反射的是哪一个类,反射哪个类返回值就是哪个类*/
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
conn=JDBCTools.getConnection();//1.获取链接
ps=conn.prepareStatement(sql);//2.获取PreparedStatement
for(int i=0;imap=new HashMap<>();
if(rs.next()){ //4.获取表的元数据(字段)
for(int i=0;ientry=(Entry)it.next();
String fileName=entry.getKey();
Object fileValue=entry.getValue();
set(t,fileName,fileValue);//6.遍历map集合存入对象
}
System.out.println(map);
return t;
}
private void set(Object obj,String fileName, Object fileValue) {
// TODO Auto-generated method stub
try {
Class cls=obj.getClass();
/*此时使用反射的意义在于,直接知道obj的直接类,而且用反射可以给私有指定字段进行赋值*/
Field field=cls.getDeclaredField(fileName);
field.setAccessible(true);//设置为true后可以直接给私有属性赋值而不调用方法
field.set(obj, fileValue);
} catch (NoSuchFieldException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*注意1.当数据库字段和类属性类型不同,统一属性
* 2.基本类型存在null时不可赋值,将类中属性改为包装类
* */
7.jdbc进行批处理:批量增删改
public class TestBatch {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement ps=null;
try {
conn=JDBCTools.getConnection();
String sql="insert into a values(?)";
ps=conn.prepareStatement(sql);
for(int i=0;i<102;i++){
ps.setInt(1, i);
ps.addBatch(); //添加到缓冲区
if(i%10==0){
ps.executeBatch(); //将添加到缓冲区的数据批量更新到数据库
ps.clearBatch(); //将缓冲区中更新完的数据清空
}
}
ps.executeBatch(); //将没更新的缓冲区更新
ps.clearBatch();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
8.DBCP连接池
commons-dbcpxxx.jar
commons-poolxxx.jar
public class TestDBCPpool {
//第一种链连接方式(无配置文件)
@Test
public void test1(){
BasicDataSource dataSource = new BasicDataSource();
//必要属性
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/sunhao");
dataSource.setUsername("root");
dataSource.setPassword("123456");
//常用属性
dataSource.setMinIdle(5); //最小空闲连接
dataSource.setMaxIdle(50); //最大空闲连接
dataSource.setInitialSize(10); //初始化连接
dataSource.setMaxActive(200); //最大连接数
dataSource.setMaxWait(5000); //最大等待时间
//获取链接
Connection conn=null;
try {
conn=dataSource.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//第二种连接方式(有配置文件)
@Test
public void test2() throws Exception{
Properties prop=new Properties();
prop.load(new FileInputStream("db.properties"));
//配置文件必须符合特定的规则才能正确读取
DataSource dataSource = BasicDataSourceFactory.createDataSource(prop);
Connection conn=null;
conn=dataSource.getConnection();
//这时候常用属性可以设置到配置文件中,当连接后就自动获取了常用属性
}
}
9.c3p0连接池(常用此连接池)
//1.构造函数不写name值就要,想dbcp一样
public class C3P0Utils {
//1、提供私有化的数据源 使用默认设置 (也可以先定义用静态代码块加载配置文件)
private static ComboPooledDataSource datasource=new ComboPooledDataSource();
//使用命名配置 (如果配置文件中有多条配置信息,就要使用下面这种方法,确定创建的是哪个数据源)
//private static ComboPooledDataSource datasource =new ComboPooledDataSource("itheima");
//2.提供对外的数据源
public static DataSource getDataSource(){
return datasource;
}
//3.提供对外的链接
public static Connection getConnection() throws SQLException{
return datasource.getConnection();
}
}
public static void closeConnection(Connection conn,Statement stmt,ResultSet rs){
try {
if(rs != null)
rs.close();
if(stmt != null)
stmt.close();
if(conn != null)
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}