PreparedSatement和C3P0连接池和DRUID连接池及JdbcTemplate总结

PreparedSatement预编译对象解决SQL注入安全漏洞。

    PreparedStatement对象继承了Statement对象。
    用法步骤:
        (1)得到连接。
        (2)拼写sql语句使用占位符(?)代替参数值的位置。
        (3)得到一个预编译对象PreparedStatement发送sql语句到数据库。
        (4)注入参数
        (5)通知数据库执行该sql语句
        (6)分析结果。

    小结一下API:
        PreparadStatement对象的获取:
            Connection下的方法:
            -- PreparedStatement prepareStatement(String sql)
        PreparadStatement对象的注入数据的方法:
            -- void setString(int parameterIndex, String parameter)
            -- void setInt(int parameterIndex, int parameter)
            -- void setObject(int parameterIndex, Object parameter)
               注入对应占位符位置:从1开始。
    总结:
        预编译对象的优点:1.SQL语句可以使用占位符。 2.安全机制更高(可以避免SQL注入)
                     3.性能好(先发送sql语句给数据库先预编译)
                     4.后期注入参数,代码十分优雅。
        结论:请使用PreparedStatement对象而不是Statement。
 */
public class LoginDemo01 {
    public static void main(String[] args) {
        /** 1.先让用户输入用户名和密码  */
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入登陆名:");
        String loginName = sc.nextLine();
        System.out.println("请输入密码:");
        String passWord = sc.nextLine();

        /** 2.校验登陆名称和密码  */
        login(loginName ,  passWord);
    }

    public static void login(String loginName, String passWord) {
        Connection con = null ;
        PreparedStatement pstm = null;
        ResultSet rs = null ;
        try{
            /** (1)得到连接。 */
            con = ConnectionFactory.getConnection();
            /** (2)拼写sql语句使用占位符(?)代替参数值的位置。 */
            String sql = "select * from tb_user where loginName = ? and passWord= ?";
            /** (3)得到一个预编译对象PreparedStatement发送sql语句到数据库先编译解析,但并未执行。*/
            pstm = con.prepareStatement(sql);
            /** (4)注入参数*/
            // 这个1代表第一个占位符注入参数值:loginName
            pstm.setString(1 , loginName);
            // 这个2代表第二个占位符注入参数值:passWord(setString会自动进行SQL注入的排查一旦发现SQL注入就返回查询失败的结果!)
            pstm.setString(2 , passWord);
            /** (5)通知数据库执行该sql语句,并得到返回结果 ,这里才是真正执行已经发过去的sql语句 */
            rs = pstm.executeQuery();
            /** (6)分析结果。 */
            if(rs.next()){
                // 登录成功了
                // 取出用户的真实用户名
                String name = rs.getString("userName");
                System.out.println(name+"登录系统成功了");
            }else{
                System.out.println("用户名或者密码错误了!");
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            ConnectionFactory.close(con , pstm , rs);
        }
    }
}
###目标:使用PreparedStatement进行数据的修改操作
小结:
    PreparedStatement是Statement的子类所以继承了以下方法:
             -- int executeUpdate()
             -- ResultSet executeQuery();

          多了各种注入占位符参数值的方法:
             -- void setString(int parameterIndex, String parameter)
             -- void setInt(int parameterIndex, int parameter)
             -- void setObject(int parameterIndex, Object parameter)
             注入对应占位符位置:从1开始。
public class PreparedStatementDemo03 {
    public static void main(String[] args) {
        Connection con = null ;
        PreparedStatement pstm = null ;
        try {
            // 1.先获取与数据库的连接
            con = ConnectionFactory.getConnection();
            // 2.拼装sql语句
            String sql = "update tb_user set userName = concat(userName,?) where id = ?";
            // 3.获取预编译对象,并同时发送sql语句到数据库预编译。
            pstm = con.prepareStatement(sql);
            // 4.开始给占位符注入参数值。
            // 5.通知数据库正式执行

            // 把id为2的数据中的userName改成原来的userName+_heima
            pstm.setString(1 , "_heima");
            pstm.setInt(2 , 2);
            int count1 = pstm.executeUpdate();
            System.out.println("修改了"+count1+"条数据!");

            // 把id为4的数据中的userName改成原来的userName+_heima
            pstm.setString(1 , "_heima");
            pstm.setInt(2 , 4);
            int count2 = pstm.executeUpdate();
            System.out.println("修改了"+count2+"条数据!");

            // 把id为6的数据中的userName改成原来的userName+_heima
            pstm.setString(1 , "_heima");
            pstm.setInt(2 , 6);
            int count3 = pstm.executeUpdate();
            System.out.println("修改了"+count3+"条数据!");

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 6.释放资源
            ConnectionFactory.close(con , pstm , null);
        }
    }
}

连接池的概念:
是提供了若干个已经做好的连接对象,可供重复使用。

连接池的作用:
1)提高创建连接的速度,快速的得到一个连接对象
2)提高连接对象的使用率
3)提高系统的性能,可以尽力避免服务器奔溃。(只是一种方案)

连接池的类API(连接池==数据源):
javax.sql.DataSource 数据源接口,又称为连接池,没有实现,
由第三方厂商来实现。我们只需要学会使用连接池即可。

JDBC全部是规范,实现交给第三方公司。

所以使用连接池必须要有3个:
1)JDBC规范接口:javax.sql.DataSource
2)连接池的实现商。
3)数据库驱动。
常用连接池的介绍:
1)阿里巴巴-德鲁伊druid连接池:Druid是阿里巴巴开源平台上的一个项目(国产的)
2)DBCP(DataBase Connection Pool)数据库连接池,
是Apache上的一个Java连接池项目,
也是Tomcat使用的连接池组件。
3)C3P0是一个开源的JDBC连接池,目前使用它的开源项目有Hibernate,Spring等。
C3P0有自动回收空闲连接功能。(经典的世界级技术)

常用连接池参数:
1.初始连接数 (initPoolSize) 一开始连接池创建的时候创建多少个连接对象在连接池中
2.最大连接数(maxPoolSize) 连接池中最多有多少个连接对象
3.最长等待时间(maxWait) 如果连接池中没有空闲连接对象,当前用户等待多久以后抛出异常,单位是毫秒。
4.最长空闲回收时间 如果一个连接对象在连接池中长时间没有人使用,
多久以后被服务器回收。有些连接池并不支持这个功能。默认是0,0表示不回收。

    所以使用连接池必须要有3个:
     1)JDBC连接池的规范接口:javax.sql.DataSource
     2)连接池的实现商。
     3)数据库驱动。

    使用步骤:
        (1)去C3P0官网下载C3p0框架包。(都是一些jar包)
        (2)导入连接池的Jar包到项目中去。
        (3)导入数据库的驱动(已经做了):连接数据库底层还是必须要依赖数据库驱动
        (4)找到C3p0的配置文件,放到src下面去。(强制性要求)
        (5)文件名默认应该使用:c3p0-config.xml
        (6)开始写源代码 实现 C3P0连接池

    C3P0构造器:
        C3P0的连接池叫 ComboPooledDataSource实现了java.sql.DataSource的规范。
            -- public ComboPooledDataSource():
                会自动读取src下的配置文件:c3p0-config.xml文件,
                来得到一个连接池对象,使用默认的配置default-config

            --  public ComboPooledDataSource(命名配置):
                会自动读取src下的配置文件:c3p0-config.xml文件,
                使用命名的配置named-config,来做连接池!

        DataSource下获取连接的方法:
            --  public Connection getConnection():获取连接
    小结:
            导入连接池的jar包,和驱动的jar包。
            在src下配置c3p0的配置文件:c3p0-config.xml
            创建连接池默认读取配置文件
            获取连接对象。
 */
public class C3P0Demo02 {
    public static void main(String[] args) {
        try {
            // 1.读取src下的默认配置文件c3p0-config.xml创建一个连接池!!
            // 使用默认的default-config做连接池
            DataSource dataSource = new ComboPooledDataSource();

             //读取src下的默认配置文件c3p0-config.xml创建一个连接池!!
            // 使用里面指定的otherc3p0做连接池
            // DataSource dataSource = new ComboPooledDataSource("otherc3p0");

            // 2.得到9个连接:保存5个,最多可用10个
            for(int i = 0 ;  i < 9 ; i++ ){
                Connection con = dataSource.getConnection();
                System.out.println(con);
//                con.close();
            }
            // 3.拿第十个连接
            Connection con = dataSource.getConnection();
            System.out.println(con);

            // 4.使用连接池的连接保存一个数据看是否可行!!
            PreparedStatement pstm = con.prepareStatement("insert into tb_user(loginName , userName) value(?,?)");
            pstm.setString(1,"tsgz");
            pstm.setString(2,"铁扇美女");
            System.out.println(pstm.executeUpdate()+"->保存成功!");
//            con.close();

            // 5.拿第11个连接
            Connection con1 = dataSource.getConnection();
            System.out.println(con1);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

    目标:Druid连接池,阿里巴巴实现的连接池使用。

    使用步骤:
     (1)去官网下载Druid框架包。(都是一些jar包)
            druid-1.0.9.jar : -- 框架包,真正需要用的。
            druid-1.0.9-javadoc.jar: -- 开发文档。
            druid-1.0.9-sources.jar: -- 框架源代码。
     (2)导入连接池的Jar包到项目中去。
     (3)导入数据库的驱动(已经做了):连接数据库还是必须要依赖数据库驱动
     (4)找到Druid的配置文件,放到src下面去。(强制性要求)
     (5)开始写源代码

      DruidDataSourceFactory.createDataSource(pro):创建连接池!
            --  public static DataSource createDataSource(Properties properties)
                参数:读取配置文件的对象。
    小结:
        把属性文件加载成属性集对象,然后转成连接池对象。
        Druid自认为:是为监控而生的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池。
 */
public class DruidDemo01 {
    public static void main(String[] args) {
        try {
            // 0.把druid.properties数据源配置文件转换成一个属性集对象Properties
            Properties pro = new Properties();
            // 加载属性文件的数据到对象pro中。
            pro.load(new FileInputStream("src/druid.properties"));

            // 1.创建阿里巴巴的连接池对象druid
            // DruidDataSourceFactory:阿里巴巴提供的创建数据源的工厂!
            // 通过属性集中的信息。把pro创建成连接池对象。
            DataSource dataSource = DruidDataSourceFactory.createDataSource(pro);

            // 2.得到9个连接:保存5个,最多可用10个
            for(int i = 0 ;  i < 9 ; i++ ){
                Connection con = dataSource.getConnection();
                System.out.println(con);
//                con.close();
            }
            // 3.拿第十个连接
            Connection con = dataSource.getConnection();
            System.out.println(con);

            // 4.使用连接池的连接保存一个数据看是否可行!!
            PreparedStatement pstm = con.prepareStatement("insert into tb_user(loginName , userName) value(?,?)");
            pstm.setString(1,"nfr");
            pstm.setString(2,"牛夫人");
            System.out.println(pstm.executeUpdate()+"->保存成功!");
//            con.close();

            // 5.拿第11个连接
            Connection con1 = dataSource.getConnection();
            System.out.println(con1);


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

德鲁伊连接工厂

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

/**
    目标:使用druid连接池做一个连接工厂。
    连接工厂:可以简化代码,我们以后可以直接拿连接。
    连接池:提高操作数据库的性能。不需要每次都创建新连接。
    小结:
        一个连接工厂通常只加载一个连接池足以!!
 */
public class DruidConnectionFactory {

    public static final String DRUID_FILE_NAME = "src/druid.properties";

    // 定义连接池对象,必须只有一个。必须定义成静态变量!!
    public static DataSource dataSource;

    // 类加载就只初始化一个连接池
    static{
        try{
            // 0.把druid.properties数据源配置文件转换成一个属性集对象Properties
            Properties pro = new Properties();
            // 加载属性文件的数据到对象pro中。
            pro.load(new FileInputStream(DRUID_FILE_NAME));

            // 1.创建阿里巴巴的连接池对象druid
            // DruidDataSourceFactory:阿里巴巴提供的创建数据源的工厂!
            // 通过属性集中的信息。把pro创建成连接池对象。
            dataSource = DruidDataSourceFactory.createDataSource(pro);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws Exception {
        // 2.从连接池中找连接返回!!
        Connection con = dataSource.getConnection();
        // 3.返回连接给调用者
        return  con;
    }

    /**
     *  3.关闭资源
     * @param con 连接对象
     * @param stm 发送SQL语句的对象
     * @param rs  结果集对象
     */
    public static void close(Connection con , Statement stm  , ResultSet rs) {
        try{
            if(stm!=null)stm.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        try{
            if(con!=null)con.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        try{
            if(rs!=null)rs.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}


import java.sql.Connection;

public class Test {
    public static void main(String[] args) throws Exception {
        for(int i = 0 ; i < 10 ; i++){
            Connection con = DruidConnectionFactory.getConnection();
            System.out.println(con);
        }
        // 第11个连接
        Connection con = DruidConnectionFactory.getConnection();
        System.out.println(con);
    }
}

目标:JdbcTemplate模板的使用。

   
        JDBC已经能够满足大部分用户最基本的需求,但是在使用JDBC时,必须自己来写代码实现所有的功能。
     如:获取PreparedStatement,设置SQL语句参数,关闭连接等步骤。

        JdbcTemplate就是Spring对JDBC的封装,目的是使JDBC更加易于使用。
     JdbcTemplate是Spring家族技术的一部分。使用JdbcTemplate编程我们只需要做以下步骤:
         1)提供SQL语句,有占位符的
         2)提供占位符的真实的值

     JdbcTemplate使用步骤:
            1.导入框架。
            2.先做数据源(已经有了阿里巴巴的德鲁伊连接池,DruidConnectionFactory.java中已经有了)
            3.拿JdbcTemplate对象
                -- public JdbcTemplate(DataSource dataSource)
                    根据数据源对象来创建JdbcTemplate对象,然后就可以方便执行SQL语句

                -- public void execute(final String sql)
                    执行代码:建表的操作.获取其他操作都可以
            4.写Sql执行执行。
    小结:
        a.有一个数据源,交给JdbcTemplate创建自己的对象
        b.拿着这个对象操作数据库即可!
        注意:数据源可以是C3P0做的数据源,也可以是阿里巴巴的德鲁伊数据源,还可以是其他任意的数据源。
 */
public class JDBCTemplate01 {
    public static void main(String[] args) {
         // 1.把数据源包装成一个高级的JDBCTemplate对象。
        // 参数就是数据源(连接池)。
        JdbcTemplate template = new  JdbcTemplate(DruidConnectionFactory.dataSource);

        // 2.直接操作数据库了。
        template.execute("delete from tb_user where id = 11");
    }
}

import com._06factory.DruidConnectionFactory;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.Date;

/**
     目标:JdbcTemplate模板的使用。DML操作。

     JdbcTemplate:
            1.导入框架。
            2.先做数据源。(C3P0,支持Druid,一切数据源都支持)
            3.拿JdbcTemplate对象
                -- public JdbcTemplate(DataSource dataSource)
                   创建JdbcTemplate对象,方便执行SQL语句
                -- public void execute(final String sql):DDL操作
                   执行代码:建表的操作:
                -- int update(String var1, Object... var2) :DML操作。
                   参数一sql语句,参数二占位符参数值
            4.写Sql执行执行。
 */
public class JDBCTemplate02 {
    @Test
    public void insertData(){
        // 1.创建JdbcTemplate对象。基于数据源
        JdbcTemplate  template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // 2.操作数据库
        String sql = "insert into tb_user(loginname, userName , passWord , create_date) " +
                "values (? ,? ,? ,?)";
        int count = template.update(sql,"qtds","齐天大圣","110",new Date());
        System.out.println("保存了"+count+"条数据!");
    }

    @Test
    public void deleteData(){
        // 1.创建JdbcTemplate对象。基于数据源
        JdbcTemplate  template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // 2.操作数据库
        String sql = "delete from tb_user where id in(? , ? )";
        int count = template.update(sql,8 , 9);
        System.out.println("删除了"+count+"条数据!");
    }

    @Test
    public void updateData(){
        // 1.创建JdbcTemplate对象。基于数据源
        JdbcTemplate  template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // 2.操作数据库
        String sql = "update tb_user set userName= ? where id = ? ";
        int count = template.update(sql,"红孩儿" , 10);
        System.out.println("修改了"+count+"条数据!");
    }
}

import com.06factory.DruidConnectionFactory;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
    目标:Template的其他功能。DQL查询

    JdbcTemplate提供的丰富的查询API

    1.查询的结果直接是返回一个整数int。  已过时
    2.查询结果是一个long。queryForLong 已过时
    3.查询结果是一个数据。 queryForObject 建议使用。
    4.查询结果是一个Map集合
    5.查询结果是一个List集合对象
    6.查询的结果是一个自定义的List集合对象 :List<User>
    7.BeanPropertyRowMapper返回自定义对象:第6点方法的优化。

 */
public class JDBCTemplate03 {
    @Test
    public void getMaxId(){
        /** 1.查询的结果直接是返回一个整数int。 */
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.写sql查询即可!
        // 以下两个api已经过时,禁止使用!
//        int rs = template.queryForInt("select max(id) from tb_user" );
//        long rs = template.queryForLong("select max(id) from tb_user" );

        /**
         * 参数一:查询语句。
         * 参数二:返回的结果类型。
         */
        // c.public <T> T queryForObject(String sql, Class<T> requiredType)
        Integer rs = template.queryForObject("select max(id) from tb_user" , Integer.class);
        System.out.println(rs);
    }

    @Test
    public void getMaxIDName(){
        // 查询出id值最大的那个人的名字
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.查询出id值最大的那个人的名字
        String name = template.queryForObject("select userName from tb_user " +
                "where id =(select max(id) from tb_user)" , String.class);
        System.out.println(name);
    }

    /**
     *  4.查询结果是一个Map集合
     */
    @Test
    public void getDataToMap(){
        // 查询出id值最大的那个人的名字
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.把数据查询成一个Map集合:查询id是13的数据
        Map<String, Object> maps = template.queryForMap("select * from tb_user where id = ?" , 13);
        System.out.println(maps);
    }

    /**
     *  5.查询结果是一个List集合对象
     */
    @Test
    public void getListMaps(){
        // 查询出id值最大的那个人的名字
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.查询出来的结果是一个List集合的对象:每个元素是一个Map集合
        // 一个Map集合代表一行数据!
        List<Map<String, Object>> datas = template.queryForList("select * from tb_user where id  < ? " , 7);
        System.out.println(datas);
    }

    /**
     *  6.查询的结果是一个自定义的List集合对象 :List<User>
     */
    @Test
    public void getUsers(){
        // 查询出id值最大的那个人的名字
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.把表中的全部用户都查询出来。
        /***
         * 参数一:查询的sql语句
         * 参数二:你来解析结果集的对象RowMapper(行映射对象 行-new User())
         */
        List<User> users = template.query("select * from tb_user", new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int i) throws SQLException {
                System.out.println("正在转:"+i);
                // 行映射成User对象的。
                // rs会自动的一行一行的读取数据,程序员要把每行数据转换成对象数据返回!!
                // 最终每行转换成的对象会自动加入到集合中去
                // i:代表当前在转换第几行
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setCreateDate(rs.getString("create_date"));
                user.setLoginName(rs.getString("loginName"));
                user.setUserName(rs.getString("userName"));
                user.setPassWord(rs.getString("passWord"));
                return user;
            }
        });
        System.out.println(users);
    }


    /**
     *   7.BeanPropertyRowMapper返回自定义对象:第6点方法的优化。
     */
    @Test
    public void getUsers1(){
        // 查询出id值最大的那个人的名字
        // a.创建JdbcTemplate对象。基于数据源
        JdbcTemplate template = new JdbcTemplate(DruidConnectionFactory.dataSource);
        // b.把用户表查询成一个List<User>集合对象
        /**
         * 参数一:查询的sql语句
         * 参数二:是结果集的处理,可以把结果集的数据自动注入到List<User>对象中去
         *          但是要求是表的列名称必须与User类对象的属性字段名称一模一样,
         *          否则自动注入失败!
         *
         *          数据库的下划线字段与Java的驼峰模式可以实现兼容和自动识别!!
         *           create_date = createDate (JdbcTemplate支持!!!)
         * */
        List<User> users = template.query("select * from tb_user" , new BeanPropertyRowMapper<>(User.class));
        System.out.println(users);
    }

}

public class User {
    private int id ;
    private String loginName ;
    private String userName ;
    private String passWord ;
    private String createDate;

    public User() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public String getCreateDate() {
        return createDate;
    }

    public void setCreateDate(String createDate) {
        this.createDate = createDate;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", loginName='" + loginName + '\'' +
                ", userName='" + userName + '\'' +
                ", passWord='" + passWord + '\'' +
                ", createDate='" + createDate + '\'' +
                '}'+"\n";
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容