第二部分 JDBC练习

前提下载: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程序,若完善,需要改成以下


第二部分 JDBC练习_第1张图片
image.png

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

你可能感兴趣的:(第二部分 JDBC练习)