Day13_包创建格式、单元测试、PS与SQL注入、连接池

一、包创建格式

dao(Data Access Object):数据访问对象        里面存放着接口
impl(implements):实现类            里面存放着接口的实现类(里面异常均为抛出)
entity/pojo/domain:实体类               里面存放着具体的对象实体类

utils:工具类                                      里面存放着需要用到的工具类

services:业务包                               里面的异常需要try。。catch。。 

二、单元测试

junit单元测试jar包:

@Before:标记他执行的这个方法是在单元测试方法前执行,一般用作初始化操作

@Test:标记方法为单元测试方法,里面包含启动器,可以启动运行。

@After:标记它执行的这个方法是在单元测试方法之后执行,一般用于释放系统资源

test:

public class CalculatorTest {
    @Test
    public void add(){
        calculator c = new calculator();
        c.add(10,20);
        Assert.assertEquals(30,30);
    }
}
public class calculator {
    public int add(int a,int b){
        return a+b;
    }
}

三者before、test、after:

public class JunitTest {
    EmpImp empImp=null;
    @Before
    public void Before(){
        Emp emp = new Emp(5,"顺顺","男","西安市");
        empImp = new EmpImp();
        System.out.println("单元测试开始了");
    }
    @Test
    public void testFindEmpById() throws SQLException {
        Emp emp = empImp.findEmpById(2);
        System.out.println(emp);
    }
    @Test
    public void testUpdate() throws SQLException {
        Emp emp = new Emp(5,"程程","男","咸阳市");
        empImp.update(emp);
        System.out.println(emp);
    }
    @After
    public void after(){
        System.out.println("寻找完毕");
    }
}

三、JDBC的PerpareStatement执行对象及使用

七大步骤:

原生写法:1.注册驱动                                        2.获得连接对象

                  3.书写SQL语句                                 4.获取执行对象

                  5.执行对象设置参数并执行               6.获得结果                        7.释放资源

后期借助工具类:

                  1.获取连接对象                                 2.书写SQL语句

                  3.获取执行对象                                 4.执行对象设置参数并执行

                  5.获得结果                                        6.释放资源

Statement与PerpareStatement对比:

1、PerpareStatement是预编译注入的,执行效率会更高,同时在查询不同值时,修改参数即可,可以重复利用。

2、Statement对象发送的SQL属于静态SQL,存在硬编码与字符串拼接,会造成SQL注入,非常不安全。

PerpareStatement对象发送的SQL都是参数化的SQL,没有SQL注入问题.。

DDL语句:execute();返回值为Boolean;                       

DML语句:executeUpdate();                        DQL语句:executeQuery();       

setxxx():解决SQL注入;        setObject()设置对象;

//PerpaceStatement执行DML语句,代码如下:
public class PreparedStatementDemo {
    public static void main(String[] args) throws SQLException {
        //获得执行对象
        Connection connnection = JdbcUtils.getConnnection();
        //书写sql语句---参数化的sql语句,可以多次赋值使用
        String sql = "insert into emploee(name,age,gender,address,salary) values(?,?,?,?,?)" ;
        //将参数化的sql发送给数据库,并且存储到PreparedStatement对象中
        PreparedStatement ps = connnection.prepareStatement(sql);
        /*PreparedStatement预编译对象中,需要给 ?  (占位符号)进行赋值
        通用方法:void setXxx(int parameterIndex, Xxx x)  :给占位符号赋值,
        参数1:第几个占位符号(从1开始)
        参数2:实际参数*/
        ps.setString(1,"亓桑") ;
        ps.setInt(2,20);
        ps.setString(3,"男");
        ps.setString(4,"西安市") ;
        ps.setDouble(5,10000.00) ;
        /*PreparedStatement预编译对象 :执行sql
        int:ps.executeUpdate():DML语句
        ResultSet:ps.executeQuery():DQL语句*/
        int count = ps.executeUpdate();
        System.out.println("影响了"+count+"行");
        //释放资源
        JdbcUtils.close(ps,connnection);
    }
}
//PerpaceStatement执行DQL语句,代码如下:
public class PreparedStatementDemo2 {
    public static void main(String[] args) throws SQLException {
        Connection connnection = JdbcUtils.getConnnection();
        String sql = "select * from emploee where id = ?" ;
        PreparedStatement ps = connnection.prepareStatement(sql);
        ps.setInt(1,7) ;
        //ResultSet executeQuery()  :DQL语句
        ResultSet rs = ps.executeQuery();
        while (rs.next()){
            int id = rs.getInt("id");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            String gender = rs.getString("gender");
            String address = rs.getString("address");
            double salary = rs.getDouble("salary");
            System.out.println(id+"\t"+name+"\t"+age+"\t"+gender+"\t"+address+"\t"+salary);
        }
        JdbcUtils.close(ps,connnection);
    }
}

五、数据连接池

一、DataSource接口

java.sql.DataSource:物理数据源的工厂是sun公司提供的接口,最终替代DriverManager:管理jdbc的驱动服务里面有一个Connection getConnection() ; 直接获取连接对象

数据库连接池优势:可以初始化连接数量,当某个线程使用某个连接对象时候,连接对象就会被这个线程持有,当这个线程结束了,释放连接对象,会将连接对象归还到数据库连接池中等待下一次利用!

二、使用步骤:

1、导入包druid-1.1.10.jar

2、配置好数据库连接池配置文件

3、获取数据库连接池(DataSource)               

4、获取连接对象(connection)

三、配置文件展示及获取连接对象

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/库名
username=root
password=756039065
initialSize=5                    //初始数据库连接对象数量
maxActive=10                //最大数据库连接对象数量
maxWait=3000               //最大等待时间(默认时间为-1,超过最大连接等待时间则会崩溃:毫秒值)

其他设置:

连接池最小空闲连接对象数量:minIdle(用于连接池空闲过多时进行回收,回收后的最小连接对象数量)
连接池最大空闲连接对象数量:maxIdle

public class DruidDemo {
    public static void main(String[] args) throws Exception {
        //1)读取配置文件
        InputStream inputStream = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
        Properties prop = new Properties();
        prop.load(inputStream);
        //2)获取数据源
        //DruidDataSourceFactory德鲁伊的数据源工厂
        //方法:protected DataSource createDataSourceInternal(Properties properties)
        //创建数据源对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
        //3)获取连接对象
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
    }
}

四、书写DruidUtils工具类

1)了解ThreadLocal类:

ThreadLocal:其虽为静态变量但与传统意义上的静态变量不同,其根据线程来产生单独的个体对象,不受类的静态变量性质的影响,详见:

【ThreadLocal 的使用场景和原理分析【并发编程】】- CSDN

//ThreadLocal测试用例
public class ThreadLocalTest {
    private static ExecutorService service = Executors.newCachedThreadPool();
    public static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
    public static void main(String[] args) {
        ThreadLocalTest.threadLocal.set(1);
//        service.execute(new Myrunable());
        service.execute(()->{
            ThreadLocalTest.threadLocal.set(2);
            System.out.println("子线程1设置为:" + threadLocal.get());
        });
        service.execute(new Myrunable1());
        service.execute(new Myrunable());
        System.out.println("主线程设置为:" + threadLocal.get());
        service.shutdown();
    }
}
class Myrunable implements Runnable{
    
    @Override
    public void run() {
//        ThreadLocalTest.threadLocal.set(3);
        System.out.println("子线程2设置为:" + ThreadLocalTest.threadLocal.get());
    }
}
class Myrunable1 implements Runnable{

    @Override
    public void run() {
//        ThreadLocalTest.threadLocal.set(4);
        System.out.println("子线程3设置为:" + ThreadLocalTest.threadLocal.get());
    }
}

2)DruidUtils工具类编写与测试

public class DruidJdbcUtils {
    /*ThreadLocal<T>类一个通过空间换时间的多线程并发问题的解决工具,它给每个线程提供了
     一个变量副本,实现了共享变量在多个线程间的隔离,比起 synchronized 通过加锁实现
     线程安全 ThreadLocal 的效率更高是一种无锁编程的实现。
     
     其虽为静态变量但与传统意义上的静态变量不同,其根据线程来产生单独的个体对象,不受类的静态变量性质的影响
     */
    public static ThreadLocal<Connection> t1 = new ThreadLocal<Connection>();
    public static DataSource ds;

    //构造方法私有化
    public DruidJdbcUtils() {
    }

    static {
        try {
            //获得配置文件
            Properties prop = new Properties();
            prop.load(new FileInputStream("D:\\1-JAVA学习\\千锋教育\\练习程序\\Jdbc\\day13_JDBC\\src\\Druid.properties"));
//            InputStream inputStream = DruidJdbcUtils.class.getClassLoader().getResourceAsStream("Druid.properties");
//            prop.load(inputStream);
            //由德鲁伊工厂获得数据库连接池对象
            ds = DruidDataSourceFactory.createDataSource(prop);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //获取数据库连接池
    public static DataSource getDataSource() {
        return ds;
    }

    //获取连接对象并为线程绑定,这样防止了一个线程获取到多个连接对象和多个线程共用一个连接对象
    public static Connection getConnection() {
        Connection conn = t1.get();
        if (conn == null) {
            try {
                conn = ds.getConnection();
                t1.set(conn);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        return conn;
    }

    public static void close(Statement st, Connection conn) {
        close(null, st, conn);
    }

    public static void close(ResultSet rs, Statement st, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (st != null) {
            try {
                st.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (conn != null) {
            try {
                conn.close();
                //将自己线程中的连接对象解绑
                t1.remove();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

测试:

public class DruidUtilsTest {
    public static void main(String[] args) throws SQLException {
        //一个线程获取一次,本次限制最大十个连接对象
        for (int i = 0; i < 10; i++) {
            Connection connection = DruidJdbcUtils.getConnection();
            System.out.println(connection);
        }
        //无限制获取会造成连接池过多,大于最大数量满足时间条件会造成程序崩溃
        DataSource dataSource = DruidJdbcUtils.getDataSource();
        for (int i = 0; i < 10; i++) {
            Connection connection1 = dataSource.getConnection();
            System.out.println(connection1);
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值