Mybatis生成器的使用

新建项目

  • 项目的目录结构如下

配置pom.xml

  1. 进入mybatis-generator官网:官网

  2. 进入mybatis-generator通过maven运行的网站:点击进入

  3. 将网站中的maven代码复制粘贴到pom中去!(前提是要把所有的需要的depend都添加进去并且配好编译环境=-=)

    <project ...>
         ...
         <build>
           ...
           <plugins>
            ...
            <plugin>
              <groupId>org.mybatis.generator</groupId>
              <artifactId>mybatis-generator-maven-plugin</artifactId>
              <version>1.4.0</version>
            </plugin>
            ...
          </plugins>
          ...
        </build>
        ...
      </project>
  4. 在generator插件中加入mysql的dependicy,因为generator需要连接数据库,如下:

    <plugin>
                    <groupId>org.mybatis.generator</groupId>
                    <artifactId>mybatis-generator-maven-plugin</artifactId>
                    <version>1.4.0</version>
                    <configuration>
                        <!--生成器的配置文件 在mybatis-generator官网找-->
                        <configurationFile>${basedir}/src/main/resources/mybatis/generator/generatorConfig.xml</configurationFile>
                        <!--重复生成覆盖原来的文件,映射文件不可行,依然是追加的方式,所以Mybatis-generator 不能运行两次-->
                        <overwrite>true</overwrite>
                    </configuration>
                    <dependencies>
                        <dependency>
                            <groupId>mysql</groupId>
                            <artifactId>mysql-connector-java</artifactId>
                            <version>${mysqlversion}</version>
                        </dependency>
                    </dependencies>
                </plugin>
  5. 因为在pom中同时引入了两个相同的mysql包,因此我们在控制mysql包版本的时候会很不方便=-=,此时应该怎么办呢?新建一个mysqlDriver的变量,然后将之前的5.1.48都替换成${mysqlDriver),如下:

    <properties>
            <java.version>1.8</java.version>
            <mysqlversion>5.1.48</mysqlversion>
        </properties>
  6. 在pom中编写以下代码

    <version>...
    <configuration>
    <!--生成器的配置文件 在mybatis-generator官网找-->
        <configurationFile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>
    <!--重复生成覆盖原来的文件,映射文件不可行,依然是追加的方式,所以Mybatis-generator 不能运行两次-->
        <overwrite>true</overwrite>
    </configuration>
    <dependicies>...

配置generatorConfig.xml

  1. 因为已经定义了生成器的配置文件,所以要在${basedir}/src/main/resources/generatorConfig.xml路径中新建一个对应的xml文件
  2. 但是一般我们工程量比较大,配置文件容易弄混,因此新建一个文件夹把这个新建的xml文件放进去,一般直接建好文件夹然后再去看配置文件,文件中的路径自己变成了相应的路径(idea可真是智能啊qwq)
  3. 进入官网,有个generatorConfig.xml常用的例子:网页链接直接复制以下代码到generatorConfig.xml中(具体代码以网页为准,因为网页会有更新)
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
      PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
      "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    
    <generatorConfiguration>
      <classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />
    
      <context id="DB2Tables" targetRuntime="MyBatis3">
        <jdbcConnection driverClass="COM.ibm.db2.jdbc.app.DB2Driver"
            connectionURL="jdbc:db2:TEST"
            userId="db2admin"
            password="db2admin">
        </jdbcConnection>
    
        <javaTypeResolver >
          <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>
    
        <javaModelGenerator targetPackage="test.model" targetProject="\MBGTestProject\src">
          <property name="enableSubPackages" value="true" />
          <property name="trimStrings" value="true" />
        </javaModelGenerator>
    
        <sqlMapGenerator targetPackage="test.xml"  targetProject="\MBGTestProject\src">
          <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
    
        <javaClientGenerator type="XMLMAPPER" targetPackage="test.dao"  targetProject="\MBGTestProject\src">
          <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
    
        <table schema="DB2ADMIN" tableName="ALLTYPES" domainObjectName="Customer" >
          <property name="useActualColumnNames" value="true"/>
          <generatedKey column="ID" sqlStatement="DB2" identity="true" />
          <columnOverride column="DATE_FIELD" property="startDate" />
          <ignoreColumn column="FRED" />
          <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />
        </table>
    
      </context>
    </generatorConfiguration>
  4. 此时第一次加载会显示有一个dtd标红,fetch一下就好了,dtd正常显示可以多很多代码提示
  5. 此时开始修改配置文件,删除整行都用commond+x,删除第7行的db2语句,修改第8行的id为MysqlTables,然后在下面设置jdbc连接的driver,username,password等参数,也可以将这些信息配置在pom文件中,但是不推荐
    <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                            connectionURL="jdbc:mysql://127.0.0.1:3306/mybatisdemo"
                            userId="root"
                            password="root">
    </jdbcConnection>
  6. 修改实体类的位置,映射文件的位置,Dao接口的位置
    <!--2.实体类的位置-->
            <javaModelGenerator targetPackage="top.leafii.mybatisgenerator.domain" targetProject="src/main/java">
                <property name="enableSubPackages" value="true" />
                <property name="trimStrings" value="true" />
            </javaModelGenerator>
            <!--3.映射文件的位置-->
            <sqlMapGenerator targetPackage="top.leafii.mybatisgenerator.mapper"  targetProject="src/main/java">
                <property name="enableSubPackages" value="true" />
            </sqlMapGenerator>
            <!--4.Dao接口的位置-->
            <javaClientGenerator type="XMLMAPPER" targetPackage="top.leafii.mybatisgenerator.mapper"  targetProject="src/main/java">
                <property name="enableSubPackages" value="true" />
            </javaClientGenerator>
  7. 添加目标表的table标签
    <table tableName="user" domainObjectName="User"></table>

运行mybatis-generator

  • 点击右侧的Maven工具栏,点击mybatis-generator的build,此时运行显示运行成功
    /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/bin/java -Dmaven.multiModuleProjectDirectory=/Users/leafii/Documents/JavaWeb/mybatis_generator -Dmaven.home=/Users/leafii/maven/apache-maven-3.6.2 -Dclassworlds.conf=/Users/leafii/maven/apache-maven-3.6.2/bin/m2.conf "-Dmaven.ext.class.path=/Applications/IntelliJ IDEA.app/Contents/plugins/maven/lib/maven-event-listener.jar" "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=61532:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Users/leafii/maven/apache-maven-3.6.2/boot/plexus-classworlds-2.6.0.jar org.codehaus.classworlds.Launcher -Didea.version2019.2.4 -s /Users/leafii/maven/apache-maven-3.6.2/conf/settings.xml org.mybatis.generator:mybatis-generator-maven-plugin:1.3.7:generate
    [INFO] Scanning for projects...
    [WARNING] 
    [WARNING] Some problems were encountered while building the effective model for leafii.top:mybatis_generator:jar:1.0-SNAPSHOT
    [WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-compiler-plugin is missing. @ line 58, column 21
    [WARNING] 
    [WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
    [WARNING] 
    [WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
    [WARNING] 
    [INFO] 
    [INFO] --------------------< leafii.top:mybatis_generator >--------------------
    [INFO] Building mybatis_generator 1.0-SNAPSHOT
    [INFO] --------------------------------[ jar ]---------------------------------
    [INFO] 
    [INFO] --- mybatis-generator-maven-plugin:1.3.7:generate (default-cli) @ mybatis_generator ---
    Wed Nov 13 09:59:14 CST 2019 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  0.885 s
    [INFO] Finished at: 2019-11-13T09:59:14+08:00
    [INFO] ------------------------------------------------------------------------

生成器优化

  1. 此时打开生成的代码发现里面很多没用的注释,怎么办呢?可以通过修改generatorConfig.xml进行设置默认不添加注释,默认参数在这里寻找:网页链接
    <commentGenerator>
                <property name="suppressAllComments" value="true"/>
            </commentGenerator>
    插入位置为
  2. 如果不删除已经生成的实体类和接口还有xml,直接重新生成,会发现实体类和接口被重写了,但是xml文件没有被覆盖而是直接被追加了,也就是说把之前的代码追加在源文件里了(代码行数直接加倍了)
  3. 在table部分修改xml代码如下,可以让生成的代码更加简洁,主要的功能还是需要我们自己去手写.
    <table tableName="user" domainObjectName="User" enableUpdateByExample="false" enableSelectByExample="false" enableCountByExample="false" enableDeleteByExample="false"/>

Mybatis-generator代码的使用

  1. 删除刚刚修改的table中添加的false选项的那几个代码,以便生成器生成功能全面的代码,点击build,生成代码
  2. 打开UserMapper.java,按下commond+shift+T 设置JUNIT4,新建junit单元测试类,选择所有方法
  3. 在测试类中编写@Before和@After代码
    @Before
        public void setUp() throws Exception {
            //读取资源文件
             inputStream = this.getClass().getClassLoader().getResourceAsStream("cfg/mybatis-config.xml");
            //创建SqlSessionFactory
             SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //获取SqlSession
             sqlSession = sqlSessionFactory.openSession(true);
            //通过SqlSession进行crud操作
             userMapper = sqlSession.getMapper(UserMapper.class);
        }
    
        @After
        public void tearDown() throws Exception {
            if(sqlSession!=null){
                sqlSession.close();
            }
            if(inputStream!=null){
                inputStream.close();
            }
        }
    
  4. 进入第一个测试类,运行时记得一定要修改相关的配置文件,记得修改log4j配置文件中UserMapper的正确路径,一定要在mybatis.config.xml中正确映射UserMapper.xml,否则无法运行!
    @Test
        public void countByExample() {
            long count = userMapper.countByExample(null);
            System.out.println(count);
        }
    执行结果:
    DEBUG [main] - ==>  Preparing: select count(*) from user 
    DEBUG [main] - ==> Parameters: 
    TRACE [main] - <==    Columns: count(*)
    TRACE [main] - <==        Row: 5
    DEBUG [main] - <==      Total: 1
    5

关于UserExample

  • UserExample大多数时候是作为筛选条件=-=

0.引子

  • 在测试类里也可以使用UserExample类
    @Test
        public void countByExample() {
            UserExample userExample = new UserExample();
            long count = userMapper.countByExample(userExample);
    //若countByExample(null)则为查询全部
            System.out.println(count);
        }
  • 运行结果
    DEBUG [main] - ==>  Preparing: select count(*) from user 
    DEBUG [main] - ==> Parameters: 
    TRACE [main] - <==    Columns: count(*)
    TRACE [main] - <==        Row: 5
    DEBUG [main] - <==      Total: 1
    5

0.5 以下两个方法实现了相同的删除功能

@Test
    public void deleteByExample() {
        UserExample userExample = new UserExample();
        userExample.or().andIdEqualTo(3);
        int i = userMapper.deleteByExample(userExample);
    }

    @Test
    public void deleteByPrimaryKey() {
        userMapper.deleteByPrimaryKey(5);
    }

自动生成的代码不能实现批量删除=-= 我们自己写一个

  • Mapper.java

    int deleteByPrimaryKey(Integer id);
    //删除一个    
    int deleteByPrimaryKeys(@Param("ids") Integer... id);
    //批量删除(Integer... id)写了之后就可以实现批量删除
  • Mapper.xml

    <delete id="deleteByPrimaryKeys" parameterType="list">
       delete from user
       where id in <foreach collection="ids" item="id" separator="," open="(" close=")">
       #{id}
     </foreach>
     </delete>
  • Test.java

    @Test
       public void deleteByPrimaryKeys() {
           userMapper.deleteByPrimaryKeys(1,2,3,4,5);
       }
  • 运行结果

    DEBUG [main] - ==>  Preparing: delete from user where id in ( ? , ? , ? , ? , ? ) 
    DEBUG [main] - ==> Parameters: 1(Integer), 2(Integer), 3(Integer), 4(Integer), 5(Integer)
    DEBUG [main] - <==    Updates: 4

1.简单查询

//查询性别为“1”且address为上海的人
UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andAddressEqualTo("上海");
        criteria.andSexEqualTo("1");
        List<User> users = userMapper.selectByExample(userExample);
        for (User u :
                users) {
            System.out.println(u);
        }
  • 运行结果
    DEBUG [main] - ==>  Preparing: select id, username, birthday, sex, address from user WHERE ( address = ? and sex = ? ) 
    DEBUG [main] - ==> Parameters: 上海(String), 1(String)
    TRACE [main] - <==    Columns: id, username, birthday, sex, address
    TRACE [main] - <==        Row: 5, 王八, 2018-07-10, 1, 上海
    DEBUG [main] - <==      Total: 1
    User{id=5, username='王八', birthday=Tue Jul 10 00:00:00 CST 2018, sex='1', address='上海'}

2.复杂查询

//查询address为北京或广州且sex为0的人
UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andAddressIn(Arrays.asList(new String[]{"上海","广州"})).andSexEqualTo("0");
        List<User> users = userMapper.selectByExample(userExample);
        for (User u :
                users) {
            System.out.println(u);
        }
  • 运行结果
    DEBUG [main] - ==>  Preparing: select id, username, birthday, sex, address from user WHERE ( address in ( ? , ? ) and sex = ? ) 
    DEBUG [main] - ==> Parameters: 上海(String), 广州(String), 0(String)
    TRACE [main] - <==    Columns: id, username, birthday, sex, address
    TRACE [main] - <==        Row: 2, 李四, 2018-07-10, 0, 上海
    DEBUG [main] - <==      Total: 1
    User{id=2, username='李四', birthday=Tue Jul 10 00:00:00 CST 2018, sex='0', address='上海'}
    注:userExample.createCriteria()与userExample.or()是等价的

3.插入用户

  • Test.java
    User user = new User();
            user.setUsername("hjkx");
            user.setId(1);
            user.setAddress("青城山");
            user.setBirthday(new Date());
            userMapper.insert(user);
            userMapper.insertSelective(user);

以上的insert()和insertSelective()方法的区别在于,insert方法会直接将未设置的属性插入到数据库中,值为null,但是如果使用insertSelective方法,就不会插入那个属性,不会传值过去 可以看看运行结果:
insert:

DEBUG [main] - ==>  Preparing: insert into user (id, username, birthday, sex, address) values (?, ?, ?, ?, ?) 
DEBUG [main] - ==> Parameters: null, hjkx(String), 2019-11-13(Date), null, 青城山(String)
DEBUG [main] - <==    Updates: 1

insertSelective

DEBUG [main] - ==>  Preparing: insert into user ( username, birthday, address ) values ( ?, ?, ? ) 
DEBUG [main] - ==> Parameters: hjkx(String), 2019-11-13(Date), 青城山(String)
DEBUG [main] - <==    Updates: 1

看看数据库:

原因是设置表格时sex的默认值为null,所以成了这样

总结:插入时使用insert而不是insertSelective

4.更新性别

  • 将目标用户的属性修改
  • Test.java
    @Test
        public void updateByPrimaryKey() {
            User user = new User();
            user.setUsername("垃圾");
            user.setId(27);
            user.setSex("1");
            user.setAddress("青城山");
            user.setBirthday(new Date());
            userMapper.updateByPrimaryKey(user);
        }
  • 运行结果
    DEBUG [main] - ==>  Preparing: update user set username = ?, birthday = ?, sex = ?, address = ? where id = ? 
    DEBUG [main] - ==> Parameters: 垃圾(String), 2019-11-13(Date), 1(String), 青城山(String), 27(Integer)
    DEBUG [main] - <==    Updates: 1
    如果更新不要用这个方法,很危险,如果只设置了需要更新的字段,那么其他字段会变成null,应该使用updateByPrimaryKeySelective,这样只需要设置需要修改的字段和主键的值就可以
    Test.java
    @Test
        public void updateByPrimaryKeySelective() {
            User user = new User();
            user.setId(27);
            user.setSex("1");
            userMapper.updateByPrimaryKeySelective(user);
        }
  • 运行结果
    DEBUG [main] - ==>  Preparing: update user SET sex = ? where id = ? 
    DEBUG [main] - ==> Parameters: 1(String), 27(Integer)
    DEBUG [main] - <==    Updates: 1

3.复杂更新

  • Test.java
    @Test
        public void updateByExampleSelective() {
            UserExample userExample = new UserExample();
            userExample.or().andAddressEqualTo("上海").andSexEqualTo("0");//条件
            User user = new User();
            user.setSex("1");
            user.setAddress("乌鲁木齐");//要更新的user
            userMapper.updateByExampleSelective(user,userExample);
        }
  • 运行结果
    DEBUG [main] - ==>  Preparing: update user SET sex = ?, address = ? WHERE ( address = ? and sex = ? ) 
    DEBUG [main] - ==> Parameters: 1(String), 乌鲁木齐(String), 上海(String), 0(String)
    DEBUG [main] - <==    Updates: 2

总结

插入数据时,使用insert方法,所有数据统统insert
更新数据时,大部分情况使用updateByPrimaryKeySelective方法,无需设置无关字段,不会修改原来的值