• [技术干货] mybatis-plus-generator-ui 可视化代码生成神器
    它提供交互式的Web UI用于生成兼容mybatis-plus框架的相关功能代码,包括Entity,Mapper,Mapper.xml,Service,Controller等。可以自定义模板以及各类输出参数,也可通过SQL查询语句直接生成代码。git地址:cid:link_0使用示例1、引入依赖 codeduidaima.com<!-- 堆代码 duidaima.com --><dependency><groupId>com.github.davidfantasy</groupId><artifactId>mybatis-plus-generator-ui</artifactId><version>2.0.1</version></dependency><!-- mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql8.version}</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency>2、新建程序入口,以main函数的方式运行 codeduidaima.compublic class GeberatorUIServer {public static void main(String[] args) {GeneratorConfig config = GeneratorConfig.builder().jdbcUrl("jdbc:mysql://111.32.222.65:3306/kp?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Hongkong").userName("root").password("root").driverClassName("com.mysql.cj.jdbc.Driver")//数据库schema,MSSQL,PGSQL,ORACLE,DB2类型的数据库需要指定//.schemaName("myBusiness")//如果需要修改entity及其属性的命名规则,以及自定义各类生成文件的命名规则,可自定义一个NameConverter实例,覆盖相应的名称转换方法,详细可查看该接口的说明:.nameConverter(new NameConverter() {/*** 自定义Service类文件的名称规则*/@Overridepublic String serviceNameConvert(String tableName) {return this.entityNameConvert(tableName) + "Service";}/*** 自定义Controller类文件的名称规则*/@Overridepublic String controllerNameConvert(String tableName) {return this.entityNameConvert(tableName) + "Controller";}})//所有生成的java文件的父包名,后续也可单独在界面上设置.basePackage("com.jincou.mybatisplus").port(8068).build();MybatisPlusToolsApplication.run(config);}}3、运行main方法访问 localhost:8068它可以把数据库所有的表都查询出来,我们可以现选择指定的表进行生成代码。同是可以选择生成哪些文件,对Controller层,也可以选择生成哪些接口。4、最终效果我们可以看到,生成的文件及目录再来看下Controller自动生成的接口注意: 因为不同的项目的接口的返回格式是不一样的,这里我们可以修改Controller模版,来生成当前我们项目所有返回接口格式。常见问题1、下载源码中怎么直接运行?不建议直接下载源码运行 ,该项目是设计为直接嵌入到对应的业务项目中使用,可以自动识别项目路径等环境变量。2、支持哪些类型的数据库?支持几乎所有主流的数据库,具体可参考mybatis-plus-generator框架的文档。需要自行引入数据库的driver包,并在 GeneratorConfig中指定driverClassName。3、保存的配置是存储到什么地方的?所有的用户保存的配置是按照basePackage分组保存到user.home目录的.mybatis-plus-generator-ui中的,不同项目的配置不会互相影响。4、启动报错问题排查大部分的启动问题都是由于依赖冲突导致的,因为mybatis-plus-generator-ui也依赖于springboot和mybatis-plus,请先检查依赖包版本是否相差过大;1.X的版本仅支持最高mp的3.4.X版本,在高版本的springboot(大于2.4)上启动也会有问题,2.0.0版本已经解决了相关的兼容性问题;
  • [技术干货] MyBatis 批量插入别再乱用 foreach 了【转载】
    近日,项目中有一个耗时较长的Job存在CPU占用过高的问题,经排查发现,主要时间消耗在往MyBatis中批量插入数据。mapper configuration是用foreach循环做的,差不多是这样。(由于项目保密,以下代码均为自己手写的demo代码)    insert into USER (id, name) values               (#{model.id}, #{model.name})      这个方法提升批量插入速度的原理是,将传统的:INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");转化为:INSERT INTO `table1` (`field1`, `field2`)  VALUES ("data1", "data2"), ("data1", "data2"), ("data1", "data2"), ("data1", "data2"), ("data1", "data2");在MySql Docs中也提到过这个trick,如果要优化插入速度时,可以将许多小型操作组合到一个大型操作中。理想情况下,这样可以在单个连接中一次性发送许多新行的数据,并将所有索引更新和一致性检查延迟到最后才进行。乍看上去这个foreach没有问题,但是经过项目实践发现,当表的列数较多(20+),以及一次性插入的行数较多(5000+)时,整个插入的耗时十分漫长,达到了14分钟,这是不能忍的。在资料中也提到了一句话:Of course don't combine ALL of them, if the amount is HUGE. Say you have 1000 rows you need to insert, then don't do it one at a time. You shouldn't equally try to have all 1000 rows in a single query. Instead break it into smaller sizes.它强调,当插入数量很多时,不能一次性全放在一条语句里。可是为什么不能放在同一条语句里呢?这条语句为什么会耗时这么久呢?我查阅了资料发现:Insert inside Mybatis foreach is not batch, this is a single (could become giant) SQL statement and that brings drawbacks:some database such as Oracle here does not support.in relevant cases: there will be a large number of records to insert and the database configured limit (by default around 2000 parameters per statement) will be hit, and eventually possibly DB stack error if the statement itself become too large.Iteration over the collection must not be done in the mybatis XML. Just execute a simple Insertstatement in a Java Foreach loop. The most important thing is the session Executor type.SqlSession session = sessionFactory.openSession(ExecutorType.BATCH); for (Model model : list) {     session.insert("insertStatement", model); } session.flushStatements();Unlike default ExecutorType.SIMPLE, the statement will be prepared once and executed for each record to insert.从资料中可知,默认执行器类型为Simple,会为每个语句创建一个新的预处理语句,也就是创建一个PreparedStatement对象。在我们的项目中,会不停地使用批量插入这个方法,而因为MyBatis对于含有的语句,无法采用缓存,那么在每次调用方法时,都会重新解析sql语句。Internally, it still generates the same single insert statement with many placeholders as the JDBC code above.MyBatis has an ability to cache PreparedStatement, but this statement cannot be cached because it contains  element and the statement varies depending on the parameters. As a result, MyBatis has to 1) evaluate the foreach part and 2) parse the statement string to build parameter mapping [1] on every execution of this statement.And these steps are relatively costly process when the statement string is big and contains many placeholders.[1] simply put, it is a mapping between placeholders and the parameters.从上述资料可知,耗时就耗在,由于我foreach后有5000+个values,所以这个PreparedStatement特别长,包含了很多占位符,对于占位符和参数的映射尤其耗时。并且,查阅相关资料可知,values的增长与所需的解析时间,是呈指数型增长的。所以,如果非要使用 foreach 的方式来进行批量插入的话,可以考虑减少一条 insert 语句中 values 的个数,最好能达到上面曲线的最底部的值,使速度最快。一般按经验来说,一次性插20~50行数量是比较合适的,时间消耗也能接受。重点来了。上面讲的是,如果非要用的方式来插入,可以提升性能的方式。而实际上,MyBatis文档中写批量插入的时候,是推荐使用另外一种方法。(可以看 http://www.mybatis.org/mybatis-dynamic-sql/docs/insert.html 中 Batch Insert Support 标题里的内容)SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH); try {     SimpleTableMapper mapper = session.getMapper(SimpleTableMapper.class);     List records = getRecordsToInsert(); // not shown       BatchInsert batchInsert = insert(records)             .into(simpleTable)             .map(id).toProperty("id")             .map(firstName).toProperty("firstName")             .map(lastName).toProperty("lastName")             .map(birthDate).toProperty("birthDate")             .map(employed).toProperty("employed")             .map(occupation).toProperty("occupation")             .build()             .render(RenderingStrategy.MYBATIS3);       batchInsert.insertStatements().stream().forEach(mapper::insert);       session.commit(); } finally {     session.close(); }即基本思想是将 MyBatis session 的 executor type 设为 Batch ,然后多次执行插入语句。就类似于JDBC的下面语句一样。Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb?useUnicode=true&characterEncoding=UTF-8&useServerPrepStmts=false&rewriteBatchedStatements=true","root","root"); connection.setAutoCommit(false); PreparedStatement ps = connection.prepareStatement(         "insert into tb_user (name) values(?)"); for (int i = 0; i < stuNum; i++) {     ps.setString(1,name);     ps.addBatch(); } ps.executeBatch(); connection.commit(); connection.close();经过试验,使用了 ExecutorType.BATCH 的插入方式,性能显著提升,不到 2s 便能全部插入完成。总结一下,如果MyBatis需要进行批量插入,推荐使用 ExecutorType.BATCH 的插入方式,如果非要使用 的插入的话,需要将每次插入的记录控制在 20~50 左右。参考资料https://dev.mysql.com/doc/refman/5.6/en/insert-optimization.htmlhttps://stackoverflow.com/questions/19682414/how-can-mysql-insert-millions-records-fasthttps://stackoverflow.com/questions/32649759/using-foreach-to-do-batch-insert-with-mybatis/40608353https://blog.csdn.net/wlwlwlwl015/article/details/50246717http://blog.harawata.net/2016/04/bulk-insert-multi-row-vs-batch-using.htmlhttps://www.red-gate.com/simple-talk/sql/performance/comparing-multiple-rows-insert-vs-single-row-insert-with-three-data-load-methods/https://stackoverflow.com/questions/7004390/java-batch-insert-into-mysql-very-slowhttp://www.mybatis.org/mybatis-dynamic-sql/docs/insert.html版权声明:本文为CSDN博主「huanghanqian」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/huanghanqian/article/details/83177178
  • [技术干货] 若依框架以及Mybatis-plus分页插件失效,数据库有多条却只查前十条-转载
     首先分析原因,我是在原来代码的基础上,重新封装了vo类返回给前端,导致的分页失效,首先看若依的分页源码是采用startPage()、getDataTable()两个方法对数据进行分页。 /**     * 设置请求分页数据     */    protected void startPage()    {        PageDomain pageDomain = TableSupport.buildPageRequest();        Integer pageNum = pageDomain.getPageNum();        Integer pageSize = pageDomain.getPageSize();        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))        {            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());            PageHelper.startPage(pageNum, pageSize, orderBy);        }    } /**     * 响应请求分页数据     */    @SuppressWarnings({ "rawtypes", "unchecked" })    protected TableDataInfo getDataTable(List<?> list)    {        TableDataInfo rspData = new TableDataInfo();        rspData.setCode(HttpStatus.SUCCESS);        rspData.setMsg("查询成功");        rspData.setRows(list);        rspData.setTotal(new PageInfo(list).getTotal());        return rspData;    }        再看下自己的代码就发现分页是对原有基础的代码进行分页操作,而我重新封装的vo类,代码中并没有对其进行分页,而是走了默认的10条数据。mybatis中解决方式:        由于若依默认用的是mybatis,先说下mybatis的解决方法,因为之前返回给前端的不是第一次查出来的数据,而是遍历又封装了一个集合返回的,所以我觉定修改查询方式,在查询时对封装的vo类进行查询,因为原有方法的数据列vo类中都存在,所以只需要修改xml文件添加方法即可,查询出来之后,再把需要自己处理的值放进去就可以保证返回的数据是第一次分页的数据。控制层:创建新的方法 @GetMapping("/list")    public TableDataInfo list(Commodity commodity)    {        startPage();     //   List<Commodity> list = commodityService.selectCommodityList(commodity);        List<CommodityVo> list =commodityService.selectVoList(commodity);        return getDataTable(list);    }在xml文件中重新定义resultMap,作为查询vo类的标志,里面的映射跟原有一样即可(查询出来的数据跟原有一样) <resultMap type="CommodityVo" id="CommodityResultVo">        <result property="id"    column="id"    />        ....        <result property="spzt"    column="spzt"    />    </resultMap>对应方法 <select id="selectList" parameterType="Commodity" resultMap="CommodityResultVo">        <include refid="selectCommodityVo"/>        <where>            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>        ...        </where>    </select>这样查出来的数据类型就是之前我们封装好的vo类的类型,从而在查出来时,我们可以处理自己的业务逻辑,并将自己需要的字段值set进去,从而解决分页失效的问题。@Override    public List<CommodityVo> selectVoList(Commodity commodity) {        List<CommodityVo> vos = commodityMapper.selectList(commodity);        for (int i = 0; i < vos.size(); i++) {            DsxsSpMoney dsxsSpMoney = new DsxsSpMoney();            dsxsSpMoney.setSpid(vos.get(i).getId());            List<DsxsSpMoney> dsxsSpMonies = spMoneyMapper.selectDsxsSpMoneyList(dsxsSpMoney);            vos.get(i).setSpmoneyList(dsxsSpMonies);        }        return vos;    }Mybatis-plus分页解决办法:       这里我用的思路都是一样的,就是查询时候自己定义多出来的数据列,查询出来之后,在将需要的数据set进去。首先引用mybatis-plus自带的分页插件@Configuration@MapperScan("com.lzq")@EnableTransactionManagementpublic class HospConfig {    /**     * 分页插件     */    @Bean    public PaginationInterceptor paginationInterceptor() {        return new PaginationInterceptor();    }}重新定义实体类:使用@TableField(exist = false)注解定义数据库中不存在的类型public class Commodity implements Serializable {     private static final long serialVersionUID=1L;//原有的实体类      private Integer id;        ...//数据库中不存在的类型    @TableField(exist = false)    private List<String> detials;    @TableField(exist = false)    private List<String> pics;    @TableField(exist = false)    private List<String> colors;    @TableField(exist = false)    private List<DsxsSpMoney> jglist;}接下来需要前端传入查询条件、页码、每页记录数来进行查询,编写控制层方法 @GetMapping("getCommodity")    public R getCompanyList(Commodity commodity,Long page,Long limit){        Page<Commodity> pageParam = new Page<>(page, limit);        QueryWrapper<Commodity> wrapper = new QueryWrapper<>();        if (commodity.getName()!=null){            wrapper.like("name", commodity.getName());        }        if (commodity.getType()!=null){            wrapper.eq("type",commodity.getType());        }        commodityService.page(pageParam,wrapper);        List<Commodity> list = pageParam.getRecords();        for (int i = 0; i < list.size(); i++) {            if (list.get(i).getPic()!=null){                String[] split = list.get(i).getPic().split(",");                ArrayList<String> arrayList = new ArrayList<>();                for (String pics:split) {                    arrayList.add(pics);                }                list.get(i).setPics(arrayList);            }            if (list.get(i).getDetial()!=null){                ...            }            if (list.get(i).getColor()!=null){                ...            }           ...        }         long total = pageParam.getTotal();         return R.ok().data("list",list).data("total",total);    }返回给前端数据以及总记录数。————————————————版权声明:本文为CSDN博主「远走与梦游」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_52210557/article/details/125629674
  • [技术干货] 【Mybatis】单表多表查询,动态SQL使用[转载]
    单表查询操作参数占位符#{}和${}#{}:相当于JDBC里面替换占位符的操作方式(#{}->“”).相当于预编译处理(预编译处理可以防止SQL注入问题)${}:相当于直接替换(desc这种关键字),但这种不能预防SQL注入select * from userinfo where username='${name}'1${} VS #{}${}是直接替换,#{}是预执行;${} 会存在SQL 注入问题,#{}不存在SQL注入问题SQL 注入UserInfo userInfo = userMapper.login("admin","' or 1='1");1mysql> select * from userinfo where username = 'admin' and password ='' or 1='1';+----+----------+----------+-------+---------------------+---------------------+-------+| id | username | password | photo | createtime          | updatetime          | state |+----+----------+----------+-------+---------------------+---------------------+-------+|  1 | admin    | admin    |       | 2021-12-06 17:10:48 | 2021-12-06 17:10:48 |     1 |+----+----------+----------+-------+---------------------+---------------------+-------+1 row in set (0.00 sec)like模糊查询用concat进行字符串拼接   <select id="findListByName" resultMap="BaseMap">        select * from userinfo where username like concat('%',#{name},'%')    </select>多表查询操作一对一多表查询一对一的多表查询:需要设置resultMap中有个association标签,property对应实体类的属性名,resultMap是关联属性的字典映射(必须要设置),columnPrefix是设置前缀,当多表查询中有相同的字段的话,就会报错<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.demo.mapper.ArticleInfoMapper">    <resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo">        <!--主键-->        <id property="id" column="id"></id>        <!--普通属性-->        <result property="updatetime" column="updatetime"></result>        <result property="title" column="title"></result>        <result property="content" column="content"></result>        <result property="createtime" column="createtime"></result>        <result property="rcount" column="rcount"></result>        <!--自定义对象属性-->        <association property="user"                     resultMap="com.example.demo.mapper.UserMapper.BaseMap"                     columnPrefix="u_">        </association>    </resultMap>    <select id="getAll" resultType="com.example.demo.model.ArticleInfo">        select a.*,u.id from articleinfo as a left join userinfo as u on a.uid = u.id;    </select>    <select id="getAll2" resultMap="BaseMap">        select a.*,u.id as u_id ,u.username as u_username,u.password as u_password from articleinfo as a left join userinfo as u on a.uid = u.id;    </select></mapper>一对多多表查询collection标签,用法同association <resultMap id="BaseMapper2" type="com.example.demo.model.UserInfo">        <!--映射主键的)(表中主键和程序实体类中的主键)-->        <id column="id" property="id"></id>        <!--普通列的映射-->        <result column="username" property="name"></result>        <result column="password" property="password"></result>        <result column="photo" property="photo"></result>        <result column="createtime" property="createtime"></result>        <result column="updatetime" property="updatetime"></result>        <!--外部关联-->        <collection property="artlist" resultMap="com.example.demo.mapper.ArticleInfoMapper.BaseMap"                    columnPrefix="a_"></collection>    </resultMap> <select id="getAll3" resultMap="BaseMapper2">        select u.*,a.id a_id,a.title a_title from userinfo u left join articleinfo a on u.id=a.uid </select>动态SQL使用if标签注册分为必填和选填,如果在添加用户的时候有不确定的字段传入,就需要使用动态标签if来判断//p是传递过来的参数名,并不是表的字段名 <insert id="add3">        insert into userinfo(username,password,        <if test="p!=null">         photo,        </if>         state)        values(#{username},#{password},        <if test="p!=null">            #{p},        </if>       #{state}) </insert>trim标签trim标签的属性:prefix:表示整个语句块,以prefix的值作为前缀suffix:表示整个语句块,以suffix的值作为后缀prefixOverrides:去掉最前面的符合条件的字符suffixOverrides:去掉最后面的符合条件的字符 <insert id="add4">        insert into userinfo        <trim prefix="(" suffix=")" suffixOverrides=",">            <if test="username!=null">                username,            </if>            <if test="password!=null">                password,            </if>            <if test="p!=null">                photo,            </if>            <if test="state!=null">                state,            </if>        </trim>        values        <trim prefix="(" suffix=")" suffixOverrides=",">            <if test="username!=null">                #{username},            </if>            <if test="password!=null">                #{password},            </if>            <if test="p!=null">                #{p},            </if>            <if test="state!=null">                #{state},            </if>        </trim>    </insert>where标签where标签首先可以帮助我们生成where,如果有查询条件,那么就生成where,如果没有查询条件,就会忽略where其次where标签可以判断第一个查询条件前面有没有and,如果有则会删除  <select id="login2" resultType="com.example.demo.model.UserInfo">        select * from userinfo        <where>        <if test="username!=null">            username=#{username}        </if>        <if test="password!=null">            and password=#{password}        </if>        </where>    </select>set标签和where的使用基本一样可以自动帮助你处理最后一个逗号,并且自动写set    <update id="update" parameterType="map">        update blog        <set>            <if test="newTitle != null">                title=#{newTitle},            </if>            <if test="newAuthor != null">                author=#{newAuthor},            </if>            <if test="newViews != null">                views = #{newViews}            </if>        </set>        <where>            <if test="id != null">                id=#{id}            </if>            <if test="title != null">                and title=#{title}            </if>            <if test="author != null">                and author=#{author}            </if>            <if test="views != null">                and views = #{views}            </if>        </where>    </update>foreach标签foreach属性:collection:参数集合的名字item:给接下来要遍历的集合起的名字open:加的前缀是什么close:加的后缀是什么separator:每次遍历之间间隔的字符串 <delete id="dels">        delete from userinfo where id in        <foreach collection="list" item="item" open="(" close=")" separator="," >            #{item}        </foreach> </delete>————————————————版权声明:本文为CSDN博主「亚太地区百大最帅面孔第101名」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/partworld/article/details/125232457
  • [技术干货] SpringBoot框架中MyBatis的应用
    MyBatis的学习1.中文文档Mybayis中文文档下载地址      MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。      MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。如何获取mybatis:maven仓库<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> githubmabatis在github中的下载地址2.持久层Dao层,Service层,Controller层3.学习过程3.1 导入依赖<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies>3.2 创建模块写一个核心配置文件<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSl=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>写一个工具类package utils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; public class MyBatisUtil { private static SqlSessionFactory sqlSessionFactory; static { try { //使用mybatis第一步获取sqlSession对象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ SqlSession sqlSession=sqlSessionFactory.openSession(); return sqlSession; } } 写一个实体类package pojo; public class User { private int id; private String name; private String pwd; public User() { } public User(int id, String name, String pwd) { this.id = id; this.name = name; this.pwd = pwd; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } }写一个接口类package dao; import pojo.User; import java.util.List; //编写一个接口类 public interface UserDao { List<User> getUserList(); } mybatis中直接通过xml文件连接数据库和实现接口类
  • [技术讨论] spring boot是Spring Data JPA和mybatis哪个用着更方便?
    spring boot是Spring Data JPA和mybatis哪个用着更方便?
  • [交流吐槽] MyBatis 缓存
    1. 什么是MyBatis缓存上文介绍的 MyBatis 延迟加载,解决的是多表关联查询情况下的效率问题,但是对于单表查询,延迟加载没有作用,MyBatis 提供了缓存机制来解决单表查询情况下的效率问题。使用缓存也是通过减少 Java 程序和数据库的交互次数来提高查询效率。比如,第一次查询出某个对象之后,MyBatis 会自动将它存入缓存,当下一次查询该对象时,可以直接从缓存中获取,而不必再次访问数据库。如果执行删除、修改操作,MyBatis 会自动清空缓存,从而保证数据的时效性与正确性。MyBatis 有两种缓存方式:一级缓存与二级缓存,二者的区别在于作用域不同。2. 一级缓存MyBatis 自带一级缓存,SqlSession 级别,默认开启,并且无法关闭。MyBatis 的一级缓存是 SqlSession 级别的缓存,在操作数据库时需要构建 SqlSession 对象,在对象里有一个 HashMap 用于存储缓存数据,不同的 SqlSession 之间缓存数据(HashMap)是互不影响的。一级缓存的作用域是 SqlSession 范围的,当在同一个 SqlSession 中执行两次相同的 sql 语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存)中,第二次查询时会从缓存中读取数据,而不再去底层进行数据库查询,从而提高了查询效率。需要注意的是,如果 SqlSession 执行 DML操作(删除和更新),并执行 commit() 操作,则 MyBatis 会自动清空 SqlSession 中的一级缓存,这样做的目的是为了保证缓存数据的时效性和正确性,避免出现读脏现象。当一个 SqlSession 结束后(SqlSession.close()),该 SqlSession 中的一级缓存也就不存在了,Mybatis 默认开启一级缓存,不需要进行任何配置。
  • [交流吐槽] Mybatis基础
    Mybatis基础1. 相关概念1.1框架介绍框架是一款半成品软件,我们可以基于这个半成品软件继续开发,来完成我们个性化的需求!简单来说, 就是"框架把一些不变的东西提前写好, 让我们能更快更好的完成程序的开发"1.2 ORM介绍ORM(Object Relational Mapping): 对象关系映射object:指的是实体对象,javabeanrelational:指的是关系型数据库,比如mysqlMapping: 映射,一 一对应的关系简单来说,ORM可以实现对象与数据库表之间的自动映射1.3 Mybatismybatis 是一个优秀的基于java的, 并且实现了ORM映射的持久层框架,它内部封装了jdbcmybatis通过xml或注解的方式实现对数据库的持久化操作MyBatis官网地址:http://www.mybatis.org/mybatis-3/2. 快速入门2.1 MyBatis开发步骤①添加MyBatis的jar包mysql-connector-java-5.1.37-bin.jarmybatis-3.5.3.jarog4j-1.2.17.jar②编写实体类(对应数据库中的表)//学生类//该类要和数据库表进行一一对应public class Student {    private Integer id;    private String name;    private Integer age;    //省略get个set方法}③编写核心配置文件SqlMapConfig.xml<?xml version="1.0" encoding="UTF-8" ?><!--MyBatis的DTD约束--><!DOCTYPE configuration         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"         "http://mybatis.org/dtd/mybatis-3-config.dtd"><!--configuration 核心根标签--><configuration>    <!--environments配置数据库环境,环境可以有多个。default属性指定使用的是哪个-->    <environments default="mysql">        <!--environment配置数据库环境  id属性唯一标识-->        <environment id="mysql">            <!-- transactionManager事务管理。 type属性,采用JDBC默认的事务-->            <transactionManager type="JDBC"></transactionManager>            <!-- dataSource数据源信息   type属性 连接池-->            <dataSource type="POOLED">                <!-- property获取数据库连接的配置信息 -->                <property name="driver" value="com.mysql.jdbc.Driver" />                <property name="url" value="jdbc:mysql://192.168.59.143:3306/数据库表名" />                <property name="username" value="数据库账户" />                <property name="password" value="数据库密码" />            </dataSource>        </environment>    </environments>    <!-- mappers引入映射配置文件 -->    <mappers>        <!-- resource属性指定映射配置文件的位置 -->        <mapper resource="StudentMapper.xml"/>    </mappers></configuration>④编写映射配置文件<?xml version="1.0" encoding="UTF-8" ?><!--MyBatis的DTD约束 直接复制--><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- mapper:核心根标签 namespace属性:名称空间 --><mapper namespace="StudentMapper">    <!--        select:查询功能的标签.   insert:添加  update:修改  delete:删除        id属性:唯一标识        resultType属性:指定结果映射对象类型        parameterType属性:指定参数映射对象类型    -->    <select id="selectAll" resultType="com.itheima.bean.Student">        SELECT * FROM student    </select>    </mapper>⑤编写测试类@Testpublic void selectAll() throws Exception{    //1.加载核心配置文件    InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");    //2.获取SqlSession工厂对象    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);    //3.通过SqlSession工厂对象获取SqlSession对象    SqlSession sqlSession = sqlSessionFactory.openSession();    //4.执行映射配置文件中的sql语句,并接收结果(参数是StudentMapper.xml中的selectAll)    List<Student> list = sqlSession.selectList("StudentMapper.selectAll");    //5.处理结果    for (Student stu : list) {        System.out.println(stu);    }    //6.释放资源    sqlSession.close();    is.close();}3. 映射配置文件3.1 配置信息<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="StudentMapper">       <insert id="insert" parameterType="student">        INSERT INTO student VALUES (#{id},#{name},#{age})    </insert>    <update id="update" parameterType="student">        UPDATE student SET name = #{name},age = #{age} WHERE id = #{id}    </update>    <delete id="delete" parameterType="int">        DELETE FROM student WHERE id = #{id}    </delete>         <select id="selectAll" resultType="student">        SELECT * FROM student    </select>    <select id="selectById" resultType="student" parameterType="int">        SELECT * FROM student WHERE id = #{id}    </select></mapper3.2 注意事项//简单类型:基本数据类型+String      复杂类型:除了基本数据类型和String1.参数是简单类型,则parameterType可以省略2.参数如果只有一个,且是简单类型时,#{id}可以随便写,都可以获取参数的值3.如果参数是复杂类型,则#{id}就相当于调用参数的getId方法,获取对应的参数值4.返回值是简单类型,则resultType可以省略5.返回值是集合类型,则resultType只写集合中元素的数据类型4. 核心配置文件4.1 引入外部properties① jdbc.propertiesdriver=com.mysql.jdbc.Driverurl=jdbc:mysql://192.168.59.143:3306/db1username=roootpassword=itheima② 引入配置文件<!--在MyBatis的核心配置文件中,引入数据库连接的配置文件--><properties resource="jdbc.properties"/>③ 获取配置信息<!-- 在MyBatis的核心配置文件中, 获取引入的properties文件中的配置信息 --><property name="driver" value="${driver}" /><property name="url" value="${url}" /><property name="username" value="${username}" /><property name="password" value="${password}" />4.2 起别名4.2.1 语法<!--起别名--><typeAliases>    <!-- 给Student类起别名为"student" -->    <typeAlias type="com.itheima.bean.Student" alias="student"/>    <!-- 给com.itheima.bean包下所有的类起别名,别名为类名的小写名字 -->    <!--<package name="com.itheima.bean"/>-->    </typeAliase></typeAliases>4.2.1 作用当给实体类起别名后, 在MyBatis映射配置文件中的参数或返回值中, 可以直接使用别名, 并且别名不区分大小写15. 补充-selectKey标签5.1 概述selectKey标签只能用在增删改语句中, 它可以在"增删改"语句执行前后, 增加对应操作.5.2 案例<insert id="insert" parameterType="student">    <selectKey keyProperty="id" order="AFTER" >        SELECT LAST_INSERT_ID()    </selectKey>    INSERT INTO student VALUES (#{id},#{name},#{age})</insert>
  • [交流吐槽] MyBatis 缓存
    1. 什么是MyBatis缓存上文介绍的 MyBatis 延迟加载,解决的是多表关联查询情况下的效率问题,但是对于单表查询,延迟加载没有作用,MyBatis 提供了缓存机制来解决单表查询情况下的效率问题。使用缓存也是通过减少 Java 程序和数据库的交互次数来提高查询效率。比如,第一次查询出某个对象之后,MyBatis 会自动将它存入缓存,当下一次查询该对象时,可以直接从缓存中获取,而不必再次访问数据库。如果执行删除、修改操作,MyBatis 会自动清空缓存,从而保证数据的时效性与正确性。MyBatis 有两种缓存方式:一级缓存与二级缓存,二者的区别在于作用域不同。2. 一级缓存MyBatis 自带一级缓存,SqlSession 级别,默认开启,并且无法关闭。MyBatis 的一级缓存是 SqlSession 级别的缓存,在操作数据库时需要构建 SqlSession 对象,在对象里有一个 HashMap 用于存储缓存数据,不同的 SqlSession 之间缓存数据(HashMap)是互不影响的。一级缓存的作用域是 SqlSession 范围的,当在同一个 SqlSession 中执行两次相同的 sql 语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存)中,第二次查询时会从缓存中读取数据,而不再去底层进行数据库查询,从而提高了查询效率。需要注意的是,如果 SqlSession 执行 DML操作(删除和更新),并执行 commit() 操作,则 MyBatis 会自动清空 SqlSession 中的一级缓存,这样做的目的是为了保证缓存数据的时效性和正确性,避免出现读脏现象。当一个 SqlSession 结束后(SqlSession.close()),该 SqlSession 中的一级缓存也就不存在了,Mybatis 默认开启一级缓存,不需要进行任何配置。
  • [开发应用] GaussDB A 8.0.0.0 GaussDB对接mybatis平台是否支持
    我们在使用GaussDB+springboot 整合过程中发现GaussDB无法兼容mybatis平台,想知道GaussDB有没有相关的整合方案?类似于postgresql的。使用JDBC进行连接数据库的时候报错:数据库连接的认证配置如下:使用的是gsjdbc200.jar驱动
  • [技术干货] Mybatis解决的问题
    1、数据库连接的创建、释放连接的频繁操作造成资源的浪费从而影响系统的性能。2、SQL语句编写在代码中,硬编码造成代码不容易维护,实际应用中SQL语句变化的可能性比较大,一旦变动就需要改变java类。3、使用preparedStatement的时候传递参数使用占位符,也存在硬编码,因为SQL语句变化,必须修改源码。4、对结果集的解析中也存在硬编码。
  • [技术干货] 说说你对Mybatis的了解
    1.Mybatis 基于java的持久层框架,它的内部封装了JDBC,让开发人员只需要关注SQL语句本身,不需要花费精力在驱动的加载、连接的创建、Statement的创建等复杂的过程。2.Mybatis 通过 XML 或注解的方式将要执行的各种的 statement 配置起来,并通过 java 对象和 statement 中的 sql 的动态参数进行映射生成最终执行的SQL 语句,最后 由mybatis框架执行SQL,并将结果直接映射为java对象 。3.采用了 ORM思想 解决了实体类和数据库表映射的问题。对 JDBC进行了封装 ,屏蔽了 JDBCAPI 底层的访问细节,避免我们与 jdbc 的 api 打交道,就能完成对数据的持久化操作。
  • [技术干货] MyBatis - 动态 sql
    动态sql  MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。动态 SQL 可以彻底处理条件地串联 SQL 字符串减少程序员的压力,让程序员将更多地精力投入开发业务中。  MyBatis 中用于实现动态 SQL 的元素主要有:If 标签可以对传入的条件进行判断#{}占位符,预编译,先编译好sql语句在取值,防止sql注入(传值时使用) ${}拼接符,会传入参数字符中,取值后再编译sql,不能防止注入 ${}适用于select * from user order by ${name} insert into user values (3,'jim',22) useGeneratedKeys="true"返回主键 keyProperty="id" 用bean下的属性接收 keyColumn="id" 数据库中的列where 标签  会进行判断,如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以 AND 或 OR 开头,它会剔除掉AND 或 OR。<select id="findUser" resultType="User"> select * from user <!-- <if test="">条件判断 <where>当条件成立时,插入where关键字,否则不插入 会取出where 语句中开头的and or 等关键字 --> <where> <if test="address!=null"> and address = #{address} </if> <if test="user_name!=null"> and user_name = #{user_name} </if> </where> </select>trim 标签  其实用 trim 也可以表示,当 WHERE 后紧随 AND 或则 OR 的时候,就去除 AND 或者 OR。prefix 前缀,prefixOverrides 覆盖首部指定内容  使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分<select id="findUser" resultType="User"> select * from user <trim prefix="where" prefixOverrides="and | or"> <if test="address!=null"> and address = #{address} </if> <if test="user_name!=null"> and user_name = #{user_name} </if> </trim> </select>模糊查询<!-- 模糊查询 1.在mapper中 user_name like '%${user_name}%' 2.在传值时候拼接好 map.put("user_name","%j%"); 3.使用concat('%',#{user_name},'%') --> <select id="findUser1" resultType="User"> select * from user <where> <if test="user_name!=null"> and user_name like concat('%',#{user_name},'%') </if> </where> </select>set 元素可以把最后一个逗号去掉<update id="update" parameterType="User"> update user <set> <if test="userName!=null"> user_name = #{userName}, </if> <if test="age!=null"> age = #{age}, </if> <if test="mobile!=null"> mobile = #{mobile}, </if> <if test="address!=null"> address = #{address} </if> </set> where id = #{id} </update>也可以使用trim实现<update id="update" parameterType="User"> update user <trim prefix="set" suffixOverrides=","> <if test="userName!=null"> user_name = #{userName}, </if> <if test="age!=null"> age = #{age}, </if> <if test="mobile!=null"> mobile = #{mobile}, </if> <if test="address!=null"> address = #{address} </if> </trim> where id = #{id} </update>Foreach元素  主要用在构建 in 条件中,它可以在 SQL 语句中进行迭代一个集合。foreach元素的属性主要有 item,index,collection,open,separator,close。  在使用 foreach 的时候最关键的也是最容易出错的就是 collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的。  – 如果传入的是单参数且参数类型是一个 List 的时候,collection 属性值为 list  – 如果传入的是单参数且参数类型是一个 array 数组的时候,collection 的属性值为array适用范围,删除多个数据  item 表示集合中每一个元素进行迭代时的别名  index 指定一个名字,用于表示在迭代过程中,每次迭代到的位置  open 表示该语句以什么开始  separator 表示在每次进行迭代之间以什么符号作为分隔符  close 表示以什么结束<delete id="deleteUser" parameterType="User"> delete from user where id IN <foreach collection="array" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete>特殊符号处理  在 mybatis 中的 xml 文件中,存在一些特殊的符号,比如:<、>、"、&、<>等,正常书写 mybatis 会报错,需要对这些符号进行转义。具体转义如下所示:  特殊字符 转义字符< &lt; > &gt; " &quot; ’ &apos; & &amp;  也可以使用<![CADTA[]]>来包裹特殊字符,但是这种方式所在的内容会被解析器忽略,应减少使用<if test="id != null"> AND <![CDATA[ id <> #{id} ]]> </if>     以上。————————————————
  • [技术干货] MyBatis - 动态 sql
    动态sql  MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。动态 SQL 可以彻底处理条件地串联 SQL 字符串减少程序员的压力,让程序员将更多地精力投入开发业务中。  MyBatis 中用于实现动态 SQL 的元素主要有:If 标签可以对传入的条件进行判断#{}占位符,预编译,先编译好sql语句在取值,防止sql注入(传值时使用) ${}拼接符,会传入参数字符中,取值后再编译sql,不能防止注入 ${}适用于select * from user order by ${name} insert into user values (3,'jim',22) useGeneratedKeys="true"返回主键 keyProperty="id" 用bean下的属性接收 keyColumn="id" 数据库中的列where 标签  会进行判断,如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以 AND 或 OR 开头,它会剔除掉AND 或 OR。<select id="findUser" resultType="User"> select * from user <!-- <if test="">条件判断 <where>当条件成立时,插入where关键字,否则不插入 会取出where 语句中开头的and or 等关键字 --> <where> <if test="address!=null"> and address = #{address} </if> <if test="user_name!=null"> and user_name = #{user_name} </if> </where> </select>trim 标签  其实用 trim 也可以表示,当 WHERE 后紧随 AND 或则 OR 的时候,就去除 AND 或者 OR。prefix 前缀,prefixOverrides 覆盖首部指定内容  使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分<select id="findUser" resultType="User"> select * from user <trim prefix="where" prefixOverrides="and | or"> <if test="address!=null"> and address = #{address} </if> <if test="user_name!=null"> and user_name = #{user_name} </if> </trim> </select>模糊查询<!-- 模糊查询 1.在mapper中 user_name like '%${user_name}%' 2.在传值时候拼接好 map.put("user_name","%j%"); 3.使用concat('%',#{user_name},'%') --> <select id="findUser1" resultType="User"> select * from user <where> <if test="user_name!=null"> and user_name like concat('%',#{user_name},'%') </if> </where> </select>set 元素可以把最后一个逗号去掉<update id="update" parameterType="User"> update user <set> <if test="userName!=null"> user_name = #{userName}, </if> <if test="age!=null"> age = #{age}, </if> <if test="mobile!=null"> mobile = #{mobile}, </if> <if test="address!=null"> address = #{address} </if> </set> where id = #{id} </update>也可以使用trim实现<update id="update" parameterType="User"> update user <trim prefix="set" suffixOverrides=","> <if test="userName!=null"> user_name = #{userName}, </if> <if test="age!=null"> age = #{age}, </if> <if test="mobile!=null"> mobile = #{mobile}, </if> <if test="address!=null"> address = #{address} </if> </trim> where id = #{id} </update>Foreach元素  主要用在构建 in 条件中,它可以在 SQL 语句中进行迭代一个集合。foreach元素的属性主要有 item,index,collection,open,separator,close。  在使用 foreach 的时候最关键的也是最容易出错的就是 collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的。  – 如果传入的是单参数且参数类型是一个 List 的时候,collection 属性值为 list  – 如果传入的是单参数且参数类型是一个 array 数组的时候,collection 的属性值为array适用范围,删除多个数据  item 表示集合中每一个元素进行迭代时的别名  index 指定一个名字,用于表示在迭代过程中,每次迭代到的位置  open 表示该语句以什么开始  separator 表示在每次进行迭代之间以什么符号作为分隔符  close 表示以什么结束<delete id="deleteUser" parameterType="User"> delete from user where id IN <foreach collection="array" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete>特殊符号处理  在 mybatis 中的 xml 文件中,存在一些特殊的符号,比如:<、>、"、&、<>等,正常书写 mybatis 会报错,需要对这些符号进行转义。具体转义如下所示:  特殊字符 转义字符< &lt; > &gt; " &quot; ’ &apos; & &amp;  也可以使用<![CADTA[]]>来包裹特殊字符,但是这种方式所在的内容会被解析器忽略,应减少使用<if test="id != null"> AND <![CDATA[ id <> #{id} ]]> </if>   
  • [技术干货] mybatis-config.xml
    <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--    外部引入db-->    <properties resource="db.properties"/>    <settings><!--        配置日志文件--><!--        <setting name="logImpl" value="STDOUT_LOGGING"/>-->        <setting name="logImpl" value="log4j"/><!--        开启A_NAME==>aName-->                <setting name="mapUnderscoreToCamelCase" valie="true"    </settings><!--   减少类型-->    <typeAliases>        <typeAlias type="com.wang.pojo.User" alias="User"/>    </typeAliases>    <environments default="development">        <environment id="development">            <transactionManager type="JDBC"/>            <dataSource type="POOLED">                <property name="driver" value="${driver}"/>                <property name="url" value="${url}"/>                <property name="username" value="${username}"/>                <property name="password" value="${password}"/>            </dataSource>        </environment>    </environments>    <mappers>        <mapper resource="com/wang/dao/UserMapper.xml"/>    </mappers></configuration>
总条数:43 到第
上滑加载中