mybatis

一、       Indroduction

Mybatis是一款优秀的持久层框架。顺便插一句,框架是什么?框架被应用于很多领域,如建筑,机械。在软件工程中,框架(Framework)是整个或者部分系统的可重用设计,是一个可复用的设计构件。可重用性,使框架的好处不言而喻。框架使开发人员从一些基础工作和一般的细节处理中解放出来,可以集中精力于系统的业务逻辑设计。Mybatis支持定制化SQL,存储过程以及高级映射。Mybatis的使用免去了原始的JDBC代码,它还可以实现一定程度的自动生成。Mybatis使用xml或者注解配置pojo和数据库记录的映射。

二、       基本步骤

1.       创建web工程

2.       导入jar包和配置日志文件

3.       配置sqlMapConfig.xml

4.       创建pojo或者类似的domain类

5.       编写sql映射文件

6.       加载sql映射文件

7.       测试

8.       例子

配置sqlMapConfig.xml

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEconfiguration

PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

   <!-- 和spring整合后 environments配置将废除-->

   <environmentsdefault="development">

      <environmentid="development">

      <!-- 使用jdbc事务管理-->

         <transactionManagertype="JDBC"/>

      <!-- 数据库连接池-->

         <dataSourcetype="POOLED">

            <propertyname="driver"value="com.mysql.jdbc.Driver"/>

            <propertyname="url"value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>

            <propertyname="username"value="root"/>

            <propertyname="password"value="1234"/>

         </dataSource>

      </environment>

   </environments>

   <mappers>

      <!-- 装载sql映射文件 -->

      <mapperresource="User.xml"/>

   </mappers>

</configuration>

创建pojo略,注意pojo属性与对应的表的字段的一一对应关系。

编写sql映射文件,注意命名空间的作用,作为映射文件内sql语句的标识

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEmapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

   <!-- namespace:命名空间作用:做sql隔离 -->

   <mappernamespace="test">

   <!-- id:sql语句的标识,可以认为是sql要执行的方法名

      parameterType:参数类型,全名或者别名

      resultType:方法返回值的类型,可以为基本类型或者引用类型,全名或别名都可以

      #{},#表示占位符,当参数为基本类型时,占位符里的值可以使用任意值占位,当参数为引用类型时,请根据引用类型的属性名填写

      综上,形成pojo类型与数据库字段的关系映射

    -->

   <selectid="queryUserById"parameterType="java.lang.Integer"resultType="com.mybatis.pojo.User">

      select * from user where id=#{haha}

   </select>

</mapper>

测试,注意创建sql会话工厂,同时载入sqlMapConfig文件,以及sql会话调用相关方法,执行sql。

   @Test

   public voidtest1() throws Exception{

      InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");

      //创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件

      SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);

      //通过工厂创建SqlSession

      SqlSession sqlSession=factory.openSession();

      //通过sql会话调用sql语句

      User u=sqlSession.selectOne("test.queryUserById", 1);

      System.out.println(u);

   }

9.       其他sql业务

执行修改数据库操作的时候,mybatis会自动开启事务,请手动提交,操作,以提交事务。否则,不执行。

注意执行不同的业务,调用sql会话中相应的方法。

1)       根据姓名模糊查询

A.     使用#占位符

   <selectid="queryUserByUsername"parameterType="java.lang.String"resultType="com.mybatis.pojo.User">

      select * from user where username like#{username}

   </select>

测试

List<User> u=sqlSession.selectList("test.queryUserByUsername","%%");

B.      使用$拼接符

拼接符里面的内容为基本数据类型,那么参数的值必须为value。使用拼接符不能防止sql注入。

   <!--

      $拼接符的使用,拼接符不会自动加引号。如'hah${username}hh',拼接符里的内容为基本数据类型,参数值必须为value。拼接符不能防止sql注入。

    -->

   <selectid="queryUserByUsername"parameterType="java.lang.String"resultType="com.mybatis.pojo.User">

      <!-- select *from user where username like #{username} -->

      select * from user where usernamelike '%${value}%'

   </select>

测试略

2)       插入操作

   <!-- 插入数据库数据

      参数列表,如果参数类中要传入的参数为引用类型的属性,请使用属性.属性,以此类推。

    -->

   <insertid="addUser"parameterType="com.mybatis.pojo.User">

      insert into user values (null,#{username},#{birthday},#{sex},#{address})

   </insert>

   @Test

   public voidtest3() throwsException{

      InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");

      //创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件

      SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);

      //通过工厂创建SqlSession

      SqlSession sqlSession=factory.openSession();

      User u=new User();

      u.setAddress("哈哈");

      u.setBirthday(new Date());

      u.setUsername("hei");

      u.setSex("1");

      sqlSession.insert("test.addUser",u);

      sqlSession.commit();

      System.out.println(u);

   }

3)       删除数据库数据

   <deleteid="deleteUserById"parameterType="int">

      delete from user where id=#{id}

   </delete>

   @Test

   public voidtest4() throws Exception{

      InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");

      //创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件

      SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);

      //通过工厂创建SqlSession

      SqlSession sqlSession=factory.openSession();

      sqlSession.delete("test.deleteUserById",26);

      sqlSession.commit();

   }

4)       更新数据库数据

   <updateid="resetUserById"parameterType="com.mybatis.pojo.User">

      update user set username=#{username},birthday=#{birthday}where id=#{id}

   </update>

   @Test

   public voidtest5() throws Exception{

      InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");

      //创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件

      SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);

      //通过工厂创建SqlSession

      SqlSession sqlSession=factory.openSession();

      User u=new User();

      u.setId(28);

      u.setBirthday(new Date());

      u.setUsername("kkss");

      sqlSession.update("test.resetUserById",u);

      sqlSession.commit();

      System.out.println(u);

   }

5)       关于插入操作时使用selectKey获得插入时创建的id。这里要数据库函数select last_insert_id();

   <insertid="addUser"parameterType="com.mybatis.pojo.User">

      <!--

         这个selectKey一般用于插入操作,插入一般使用pojo传参,所以,可以将主键的值返回给这个pojo里面的属性接收

         keyProperty:主键要返回的pojo类的属性,并且将主键值赋给这个属性,类型要一致

         order:获得主键的时机,after之后,或者before之前

         resultType:获得后返回的类型

       -->

      <selectKeykeyProperty="id"order="AFTER"resultType="String">

         select last_insert_id();

      </selectKey>

      insert into user values (null,#{username},#{birthday},#{sex},#{address})

   </insert>

   @Test

   public voidtest3() throwsException{

      InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");

      //创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件

      SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);

      //通过工厂创建SqlSession

      SqlSession sqlSession=factory.openSession();

      User u=new User();

      u.setAddress("哈哈");

      u.setBirthday(new Date());

      u.setUsername("hei");

      u.setSex("1");

      System.out.println(u.getId());

      sqlSession.insert("test.addUser",u);

      sqlSession.commit();

      System.out.println(u.getId());

      System.out.println(u);

   }

6)       关于为数据库id字段插入uuid作为id。结合selectKey,使用order=”BEFORE”,在插入数据前产生uuid,请放入pojo。请使用数据库函数selectuuid();

   </insert>

   <!--

      在插入数据前,通过数据库函数获得uuid,再使用selectKey获得这个uuid,赋值给pojo对应数据库id字段的属性。

    -->

   <insertid="addUser2"parameterType="com.mybatis.pojo.User2">

      <!--

         这个selectKey一般用于插入操作,插入一般使用pojo传参,所以,可以将主键的值返回给这个pojo里面的属性接收

         keyProperty:主键要返回的pojo类的属性,并且将主键值赋给这个属性,类型要一致

         order:获得主键的时机,after之后,或者before之前

         resultType:获得后返回的类型

         业务逻辑:在插入数据前,获得uuid放入pojo,插入时即可将uuid表示的id也插入。

       -->

      <selectKeykeyProperty="id"order="BEFORE"resultType="String">

         select uuid();

      </selectKey>

      insert into user2 values (#{id},#{username},#{birthday},#{sex},#{address})

   </insert>

   @Test

   public voidtestUuid() throwsException{

      InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");

      //创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件

      SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);

      //通过工厂创建SqlSession

      SqlSession sqlSession=factory.openSession();

      User2 u=new User2();

      u.setAddress("哈哈");

      u.setBirthday(new Date());

      u.setUsername("hei");

      u.setSex("1");

      System.out.println(u.getId());

      sqlSession.insert("test.addUser2",u);

      sqlSession.commit();

      System.out.println(u.getId());

      System.out.println(u);

   }

三、       Dao层开发

(一)            原始的dao层开发

核心步骤:

1.       创建dao层接口和实现类

2.       编写sql映射xml

3.       在dao层实现类使用sql会话,实现业务

4.       为了节省资源,将SqlSessionFactory的创建放在更全局的位置

5.       SqlSession由于是多线程的,为了避免线程干扰,SqlSession的作用域不可以无理由扩大,所以SqlSession最好定义在使用单个使用SqlSession的请求或方法里。

6.       例子

编写sql映射xml

略,同上

创建dao层接口和类,注意对SqlSessionFactory的处理

public interface UserDao {

   public User queryUserById(intid);

   public voidaddUser(User u);

}

public class UserDaoImpl implements UserDao{

   //使用SqlSessionFactory进行sql会话

   private SqlSessionFactorysqlSessionFactory;

   public UserDaoImpl(SqlSessionFactorysqlSessionFactory){

      this.sqlSessionFactory=sqlSessionFactory;

   }

   @Override

   public User queryUserById(intid) {

      SqlSession sqlSession=sqlSessionFactory.openSession();

      User u=sqlSession.selectOne("user.queryUserById", 1);

      return u;

   }

}

创建service层类和接口

public interface UserService {

   User queryUserById(intid);

}

public class UserServiceImpl implements UserService{

   private staticSqlSessionFactory sqlSessionFactory;

   private staticInputStream inputStream;

   static {

      try {

         InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");

         sqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream);

      } catch (IOExceptione) {

         // TODO Auto-generated catch block

         e.printStackTrace();

      }

   }

   private staticUserDao ud=new UserDaoImpl(sqlSessionFactory);

   public User queryUserById(intid) {

      return ud.queryUserById(id);

   }

}

测试略

7.       其他数据库操作的例子,注意修改类操作,需要提交sql会话。

(二)            接口映射动态代理方式

这里出现了动态代理这个词。在spring的aop中,其底层采用的是动态代理,不管是jdk的还是cglib的动态代理实现,都有一个代理类的东西,代理委托对象实现某些业务。在这个mybatis的接口映射动态代理这里,既然是代理,就有委托对象和代理对象,委托对象是接口及其中的方法,代理对象是sql映射xml,相当于xml中直接实现了接口里的方法。本来接口,需要实现类实现接口的方法的,但是接口委托给xml做了,也可以看作xml代理了实现类的工作,然后实现类并没有创建出来,明确的说是xml代理了本应该由实现类做的工作。这样,在实现动态代理时,需要对应好接口和xml的相关参数。

接口与映射xml的对应要求:

1.       接口和xml需要同包同名。

2.       Xml中的namespace为接口的全路径名称,这样当sqlMapConfig.xml装载了映射xml后,才能找到接口。实际上,是根据SqlSession获取接口,获取的同时传入这个接口的路径,在这两个过程中会试图建立接口和xml的连接关系,成功后则接口的实例可以调用自己的方法,并通过xml代理实现这个方法。

3.       接口的方法名与xml中相应的sql会话的id值一致

4.       接口的方法中的参数与相应的sql会话中的paremeterType的值一致

5.       接口的方法中的返回类型与相应的sql会话中的resultTyoe的值一致

6.       例子

创建接口类

public interface UserMapper {

   public User queryUserById(intid);

}

创建xml

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEmapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

   <!-- namespace:命名空间作用:做sql隔离 -->

   <mappernamespace="com.mybatis.mapper.UserMapper">

   <!-- id:sql语句的标识,可以认为是sql要执行的方法名

      parameterType:参数类型,全名或者别名

      resultType:方法返回值的类型,可以为基本类型或者引用类型,全名或别名都可以

      #{},#表示占位符,当参数为基本类型时,占位符里的值可以使用任意值占位,当参数为引用类型时,请根据引用类型的属性名填写

      综上,形成pojo类型与数据库字段的关系映射

    -->

   <selectid="queryUserById"parameterType="java.lang.Integer"resultType="com.mybatis.pojo.User">

      select* from user where id=#{haha}

   </select>

   <!--

      $拼接符的使用,拼接符不会自动加引号。如'hah${username}hh',拼接符里的内容为基本数据类型,参数值必须为value。拼接符不能防止sql注入。

    -->

   <selectid="queryUserByUsername"parameterType="java.lang.String"resultType="com.mybatis.pojo.User">

      <!-- select* from user where username like #{username} -->

      select * from user where usernamelike '%${value}%'

   </select>

</mapper>

测试

public class TestMapper {

   private  SqlSessionFactorysqlSessionFactory;

   private  InputStreaminputStream;

   {

      try {

         InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");

         sqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream);

      } catch (IOExceptione) {

         // TODO Auto-generated catch block

         e.printStackTrace();

      }

   }

   @Test

   public voidtest1(){

      SqlSession sqlSession=sqlSessionFactory.openSession();

      UserMapper userMapper=sqlSession.getMapper(UserMapper.class);

      System.out.println(UserMapper.class);

      User u=userMapper.queryUserById(1);

      System.out.println(u);

   }

}

7.       关于增删改的操作。这些更新类型的操作需要sql会话提交,才能生效。例子略。

四、       sqlMapConfig.xml文件的一些配置

(一)            propertyies属性配置

propertyies,用于配置连接数据库的相关信息,好处是分离代码,降低耦合。

配置数据库信息的文件db.properties

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8

jdbc.username=root

jdbc.password=1234

修改sqlMapConfig.xml的配置

   <!-- 配置连接池配置文件 -->

   <propertiesresource="db.properties"></properties>

   <environmentsdefault="development">

      <environmentid="development">

      <!-- 使用jdbc事务管理-->

         <transactionManagertype="JDBC"/>

      <!-- 数据库连接池-->

         <dataSourcetype="POOLED">

            <propertyname="driver"value="${jdbc.driver}"/>

            <propertyname="url"value="${jdbc.url}"/>

            <propertyname="username"value="${jdbc.username}"/>

            <propertyname="password"value="${jdbc.password}"/>

         </dataSource>

      </environment>

   </environments>

(二)            typeAliases数据类型的别名

mybatis已经内置了一些数据的别,比如,

别名

映射的类型

_byte

byte

_long

long

_short

short

_int

int

_integer

int

_double

double

_float

float

_boolean

boolean

string

String

byte

Byte

long

Long

short

Short

int

Integer

integer

Integer

double

Double

float

Float

boolean

Boolean

date

Date

decimal

BigDecimal

bigdecimal

BigDecimal

map

Map

使用typeAliases属性也可以定义别名

请注意sqlMapConfig.xml中标签的前后顺序,见xml的提示。

在sqlMapConfig.xml中定义别名

   <typeAliases>

      <!--

         alias:别名

         type:类型

       -->

      <typeAliasalias="haha"type="com.mybatis.pojo.User"></typeAlias>

   </typeAliases>

使用别名

   <selectid="queryUserById"parameterType="java.lang.Integer"resultType="haha">

      select * from user where id=#{haha}

   </select>

Mybatis提供了扫描包,自动定义别名的功能,将类名定义为别名,不区分大小写,一般采用驼峰表示法。

开启别名自动扫描

   <typeAliases>

      <packagename="com.mybatis.pojo"/>

   </typeAliases>

(三)            mapper映射器配置

在sqlMapConfig.xml中提供了3种方式加载映射文件

resource

class

package

   <mappers>

      <!-- 装载sql映射文件 -->

      <mapperresource="User.xml"/>

      <mapperresource="UserDao.xml"/>

      <mapperclass="com.mybatis.mapper.UserMapper"/>

      <packagename="com.mybatis.mapper"/>

   </mappers>

五、       对象关系映射文件中sql语句的参数与返回值

(一)            Sql语句参数类型

缺省parameterType,表示sql映射的方法无参。

1.       基本数据类型

   <selectid="queryUserById"parameterType="java.lang.Integer"resultType="user">

      select * from user where id=#{haha}

   </select>

占位符的值可以任意

2.       未使用引用类型属性的引用数据类型

   <updateid="resetUserById"parameterType="com.mybatis.pojo.User">

      update user set username=#{username},birthday=#{birthday}where id=#{id}

   </update>

注意:占位符的值与引用类型属性的对应一致

3.       使用引用类型属性的引用数据类型

这种类型,一般称为vo。Vo一般用于商业逻辑层和表示层。使用vo的好处,降低耦合,提高内聚。

例子:

编写映射sql语句

   <!-- 使用vo的方式 -->

   <selectid="queryUserByUserAndSex"parameterType="com.mybatis.pojo.QueryVo"resultType="user">

      select * from user where usernamelike '%${user.username}%' and sex=#{user.sex}

   </select>

测试

   @Test

   public voidtest4(){

      SqlSession sqlSession=sqlSessionFactory.openSession();

      UserMapper userMapper=sqlSession.getMapper(UserMapper.class);

      User u=new User();

      u.setUsername("王");

      u.setSex("2");

      QueryVo qv=new QueryVo();

      qv.setUser(u);

      User qu=userMapper.queryUserByUserAndSex(qv);

      System.out.println(qu);

   }

(二)            Sql语句返回类型

1.       Void

缺省resultType表示sql映射的方法无返回值。

   <updateid="resetUserById"parameterType="com.mybatis.pojo.User">

      update user set username=#{username},birthday=#{birthday}where id=#{id}

   </update>

2.       引用数据类型

   <selectid="queryUserById"parameterType="java.lang.Integer"resultType="user">

      select * from user where id=#{haha}

   </select>

3.       基本数据类型

   <!-- 返回基本数据类型 -->

   <selectid="queryUserCount"resultType="int">

      select count(*) from user

   </select>

4.       集合

请使用集合的泛型作为返回值

   <selectid="queryUserByUsername"parameterType="java.lang.String"resultType="com.mybatis.pojo.User">

      <!-- select* from user where username like #{username} -->

      select * from user where usernamelike '%${value}%'

   </select>

六、    Sql语句的控制流程标签的使用

使用控制流程标签可以实现sql的动态效果

1.  if 

  <selectid="queryUserByOptions"parameterType="user"resultType="user">

      select * from user where 1=1

      <iftest="username!=nulland username!=''">

         and username like '%${username}%'

      </if>

      <iftest="sex!=null andsex!=''">

         and sex=#{sex}

      </if>

   </select>

使用where标签后

   <selectid="queryUserByOptions"parameterType="user"resultType="user">

      select * from user

      <!-- where 自动添加where条件以及去掉where关键字后的and -->

      <where>

         <iftest="username!=nulland username!=''">

            and username like '%${username}%'

         </if>

         <iftest="sex!=null andsex!=''">

            and sex=#{sex}

         </if>

      </where>

   </select>

使用sql标签封装sql语句,并使用include标签调用sql标签的id后

   <sql id="userOptions">

      <!-- where 自动添加where条件以及去掉where关键自后的and -->

      <where>

         <iftest="username!=nulland username!=''">

            and username like '%${username}%'

         </if>

         <iftest="sex!=null andsex!=''">

            and sex=#{sex}

         </if>

      </where>

   </sql>

   <selectid="queryUserByOptions"parameterType="user"resultType="user">

      select * from user

      <includerefid="userOptions"></include>

   </select>

2.  foreach

主要参数:

collection:要循环的集合的名称

item:每次循环将结果存放为的值

open:循环开始的语句

close:循环结束的语句

separator:每次循环的值的分隔符

例子:

   <!-- 使用foreach组织数组式条件 -->

   <selectid="queryUserByIds"parameterType="queryVo"resultType="user">

      select * from user

      <where>

         <iftest="ids!=null">

            <!--

                collection:要循环的集合的名称

                item:每次循环将结果存放为的值

                open:循环开始的语句

                close:循环结束的语句

                separator:每次循环的值的分隔符

             -->

            <foreachcollection="ids"item="id"open="id in ("close=")"separator=",">

                #{id}

            </foreach>

        

         </if>

      </where>

   </select>

测试略

使用sql标签后

   <sqlid="idsOption">

      <where>

         <iftest="ids!=null">

            <!--

                collection:要循环的集合的名称

                item:每次循环将结果存放为的值

                open:循环开始的语句

                close:循环结束的语句

                separator:每次循环的值的分隔符

             -->

            <foreachcollection="ids"item="id"open="id in ("close=")"separator=",">

                #{id}

            </foreach>

         </if>

      </where>

   </sql>

   <!-- 使用foreach组织数组式条件 -->

   <selectid="queryUserByIds"parameterType="queryVo"resultType="user">

      select * from user

      <includerefid="idsOption"></include>

   </select>

七、       多表关联查询的映射关系

(一)            关联查询的一对一关系

1.       方式一:非主动设置,Po类属性与数据库查询表的字段根据名称一一对应。

注意上述的表为查询表,而非原表。

例子:

创建po类对应数据查询表字段,利用了继承,简化了代码,提高了重用

public class OrderOfUser extends Orders{

   private intuid;

   private Stringusername;//用户姓名

   private Stringsex;//性别

   private Datebirthday;//生日

   private Stringaddress;//地址

   public intgetUid() {

      return uid;

   }

   public voidsetUid(intuid){

      this.uid =uid;

   }

   public String getUsername() {

      return username;

   }

   public voidsetUsername(String username){

      this.username =username;

   }

   public String getSex() {

      return sex;

   }

   public voidsetSex(String sex){

      this.sex =sex;

   }

   public Date getBirthday() {

      return birthday;

   }

   public voidsetBirthday(Date birthday){

      this.birthday =birthday;

   }

   public String getAddress() {

      return address;

   }

   public voidsetAddress(String address){

      this.address =address;

   }

   @Override

   public String toString() {

      return "OrderOfUser [uid=" + uid + ", username="+ username+ ", sex="+ sex+ ", birthday=" + birthday

            + ", address=" + address + "]" +"\n";

   }

}

编写sql语句映射

   <!-- 联合查询的一对一关系 -->

   <selectid="queryOrder"resultType="orderOfUser">

      SELECT o.*,u.id uid,u.username,u.address,u.sex,u.birthdayFROM orders o,USER u WHERE o.user_id=u.id

   </select>

2.       方式二:主动设置po类和数据库查询表的映射关系

当sql语句返回的类型为引用类型,并且查询表中的字段为返回的引用类型的引用类型的属性的时候,可以手动设置查询表字段与返回类型的引用数据类型的映射关系。

语法:

<select id=””parameterType=”” resultMap=”唯一标识”>

       ……

</select>

<resultMap id=”唯一标识” type=”接收sql返回值的类型”>

       <id column=”” property=”” />

       <!- - 一般认为这个id为主键字段与模型领域属性的映射关系专用的,经过尝试,将result换成id,或者id换成result,也可以得到一样的结果-- >

       <result column=”” property=”” />

       <result column=”” property=”” />

       <!- -association设置po类中引用类型属性与查询表字段的映射关系

              Type:设置引用类型属性的类型

              Property:设置引用类型属性的名称

 -- >

       <association property=”” type=””>

<id column=”” property=”” />

<!- - 传说这个id为主键字段与模型领域属性的映射关系专用的,经过尝试,将result换成id,或者id换成result,也可以得到一样的结果-- >

              <resultcolumn=”” property=”” />

              <resultcolumn=”” property=”” />

       </association>

</resultMap>

例子:

创建po类

public class User {

   private intid;

   private Stringusername;//用户姓名

   private Stringsex;//性别

   private Datebirthday;//生日

   private Stringaddress;//地址

   public intgetId() {

      return id;

   }

   public voidsetId(intid) {

      this.id =id;

   }

   public String getUsername() {

      return username;

   }

   public voidsetUsername(String username){

      this.username =username;

   }

   public String getSex() {

      return sex;

   }

   public voidsetSex(String sex){

      this.sex =sex;

   }

   public Date getBirthday() {

      return birthday;

   }

   public voidsetBirthday(Date birthday){

      this.birthday =birthday;

   }

   public String getAddress() {

      return address;

   }

   public voidsetAddress(String address){

      this.address =address;

   }

   @Override

   public String toString() {

      return "User [id=" + id + ", username="+ username+ ", sex="+ sex

            + ", birthday=" + birthday + ", address="+ address+ "]"+"\r\n";

   }

}

public class Orders {

   private Integerid;

    private IntegeruserId;

    private Stringnumber;

    private Datecreatetime;

    private Stringnote;  

    private Useruser;

    public User getUser() {

      return user;

   }

   public voidsetUser(User user){

      this.user =user;

   }

   public Integer getId() {

        returnid;

    }

    public void setId(Integer id) {

        this.id =id;

    }

    public Integer getUserId() {

        returnuserId;

    }

    public void setUserId(Integer userId) {

        this.userId =userId;

    }

    public String getNumber() {

        returnnumber;

    }

    public void setNumber(String number) {

        this.number =number==null?null:number.trim();

    }

    public Date getCreatetime() {

        returncreatetime;

    }

    public void setCreatetime(Date createtime) {

        this.createtime =createtime;

    }

    public String getNote() {

        returnnote;

    }

    public void setNote(String note) {

        this.note =note==null?null:note.trim();

    }

   @Override

   public String toString() {

      return "Orders [id=" + id + ", userId="+ userId+ ", number=" + number+ ", createtime=" + createtime

            + ", note=" + note + ", user="+ user+ "]";

   }  

}
   <!-- 手动设置返回类中引用类型属性与查询表字段的映射关系 -->

   <resultMaptype="orders"id="orderOfUserMap">

      <!--

         id:结果映射的标识

         type:sql返回类型

       -->

       <!--

         id标签,指定查询表主键与javapo类的映射关系

         result,指定其他字段与po类的映射关系

        -->

       <idcolumn="id"property="id"/>

       <resultcolumn="user_id"property="userId"/>

       <resultcolumn="number"property="number"/>

       <resultcolumn="createtime"property="createtime"/>

       <resultcolumn="note"property="note"/>

       <!--

         association:指定返回po类的引用类型属性与属性值的对应关系

        -->

       <associationproperty="user"javaType="user">

         <resultcolumn="username"property="username"/>

         <resultcolumn="uid"property="id"/>

         <resultcolumn="address"property="address"/>

         <resultcolumn="sex"property="sex"/>

         <resultcolumn="birthday"property="birthday"/>

       </association>

   </resultMap>

   <selectid="queryOrder2"resultMap="orderOfUserMap">

      SELECT o.*,u.id uid,u.username,u.address,u.sex,u.birthdayFROM orders o,USER u WHERE o.user_id=u.id

   </select>

测试略

(二)            关联查询的一对多关系

一对多的关系,指主表的id对用的关联表中会产生多个结果的关系。

比如,一个学生表,一个课程表,学生表中学生id,关联课程表中学生id外键的时候,可能有多个课程的id对应这个学生的id,这样就形成了一对多的关系。

一对多只能通过手动设置的方式实现。

语法:

<select id=””parameterType=”” resultMap=”唯一标识”>

       ……

</select>

<resultMap id=”唯一标识” type=”接收sql返回值的类型”>

       <id column=”” property=”” />

       <!- - 一般认为这个id为主键字段与模型领域属性的映射关系专用的,经过尝试,将result换成id,或者id换成result,也可以得到一样的结果-- >

       <result column=”” property=”” />

       <result column=”” property=”” />

       <!- -collection设置 po类中集合类型属性与查询表字段的映射关系,这个集合类型就是多的一方

              Property:集合类型属性在其类中的名称

              ofType:集合的泛型的类型

 -- >

<collection property=”” ofType=””>

<id column=”” property=”” />

<!- - 传说这个id为主键字段与模型领域属性的映射关系专用的,经过尝试,将result换成id,或者id换成result,也可以得到一样的结果-- >

              <resultcolumn=”” property=”” />

              <resultcolumn=”” property=”” />

       </collection>

</resultMap>

例子:

创建返回类型的类,也就是一的一方,注意将多的一方作为泛型的集合定义为返回类的属性

关键代码部分:

   private List<Orders>orders;

  

  

   public List<Orders> getOrders() {

      return orders;

   }

   public voidsetOrders(List<Orders> orders) {

      this.orders =orders;

   }

编写sql语句的一对多映射配置

   <!-- 联合查询的一对多映射关系 -->

   <selectid="queryOrder3"resultMap="userOfOrderMap">

      SELECT u.*,o.id oid,o.user_id,o.number,o.createtime,o.noteFROM orders o,USER u WHERE o.user_id=u.id

   </select>

   <!-- 设置结果映射 -->

   <resultMapid="userOfOrderMap"type="user">

      <idcolumn="id"property="id"/>

      <resultcolumn="username"property="username"/>

      <resultcolumn="address"property="address"/>

      <resultcolumn="sex"property="sex"/>

      <resultcolumn="birthday"property="birthday"/>

      <!-- collection用于设置po类中集合类属性,也就是对应的多的一方的映射关系

         请注意声明集合泛型的类型时,使用ofType

       -->

      <collectionproperty="orders"ofType="orders">

         <idcolumn="oid"property="id"/>

         <resultcolumn="user_id"property="userId"/>

         <resultcolumn="number"property="number"/>

         <resultcolumn="createtime"property="createtime"/>

         <resultcolumn="note"property="note"/>

      </collection>

   </resultMap>

八、       Spring整合mybatis

整合spring的意义在于促进低耦合,高内聚。将能交给spring管理的交给spring管理,因为spring存在的意义之一就是IoC。所以,mybatis中的类以及映射xml文件都可以给spring。具体来说就是

SqlSessionFactory交由springbean组件实现;

SqlSession由spring创建;

映射动态代理形式,从spring获得代理对象;

数据库连接交给spring实现。

整合步骤:

1.       创建一个web工程

2.       导入需要的jar

Spring的jar包,mybatis的jar包,spring整合mybatis的jar包,mysql驱动包,连接池的jar包。

3.       Mybatis配置文件sqlMapConfig.xml

4.       Spring核心配置文件applicationContext.xml

5.       编写dao层接口类或者mappersql语句文件

6.       创建pojo

7.       测试

8.       例子

1)       Dao层开发的方式

注意dao层开发中,可以使用dao层类继承SqlSessionDaoSupport的方式,简化开发。

Mybatis配置文件sqlMapConfig.xml

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEconfiguration

PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

   <propertiesresource="db.properties"></properties>

   <typeAliases>

      <packagename="com.mybatis.pojo"></package>

   </typeAliases>

   <mappers>

      <mapperresource="user.xml"></mapper>

     

      <!--

         在spring中配置之后,在我们的mybatis中,就不需要去自动扫描

        -->

   <!-- <packagename="com.mybatis.mapper"></package> -->

   </mappers>

</configuration>

Spring核心配置文件applicationContext.xml

<?xmlversion="1.0"encoding="UTF-8"?>

<beansxmlns="http://www.springframework.org/schema/beans"

   xmlns:context="http://www.springframework.org/schema/context"xmlns:p="http://www.springframework.org/schema/p"

   xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsd

   http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsd

   http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd

   http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-4.0.xsd">

      <!-- 加载配置文件 -->

   <context:property-placeholderlocation="classpath:db.properties"/>

   <!-- 数据库连接池 -->

   <beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"

      destroy-method="close">

      <propertyname="driverClassName"value="${jdbc.driver}"/>

      <propertyname="url"value="${jdbc.url}"/>

      <propertyname="username"value="${jdbc.username}"/>

      <propertyname="password"value="${jdbc.password}"/>

      <propertyname="maxActive"value="10"/>

      <propertyname="maxIdle"value="5"/>

   </bean>

   <!-- mapper配置 -->

   <!-- 让spring管理sqlsessionfactory使用mybatis和spring整合包中的 -->

   <beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">

      <!-- 数据库连接池 -->

      <propertyname="dataSource"ref="dataSource"/>

      <!-- 加载mybatis的全局配置文件 -->

      <propertyname="configLocation"value="classpath:sqlMapConfig.xml"/>

   </bean>

  

   <!-- 装载dao层实现类的bean组件,同时注入sql会话工厂 -->

   <beanid="userDao"class="com.mybatis.dao.UserDaoImpl">

      <propertyname="sqlSessionFactory"ref="sqlSessionFactory"/>

   </bean>

</beans>

Dao层接口和类,注意类继承SqlSessionDaoSupport简化开发

public interface UserDao {

   public User queryUserById(intid);

}

public class UserDaoImpl extends SqlSessionDaoSupportimplements UserDao{

   public User queryUserById(intid) {

      SqlSession sqlSession=this.getSqlSession();

      User u=sqlSession.selectOne("user.queryUserById",id);

      return u;

   }

}

创建pojo略,测试

   @Test

   public voidtest1(){

      ApplicationContext ac=newClassPathXmlApplicationContext("applicationContext.xml");

      UserDao ud=(UserDao)ac.getBean("userDao");

      User u=ud.queryUserById(1);

      System.out.println(u);

   }

2)       Mapper动态代理的形式

核心步骤:

A.     创建sql会话接口映射包,创建接口和mapper映射文件

B.      Spring核心配置文件中,装配代理类的bean组件

C.      例子

接口映射包内容

public interface UserMapper {

   public User queryUserById(intid);

}
<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEmapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace:命名空间作用:做sql隔离

    之后会有规范

-->

<mappernamespace="com.mybatis.mapper.UserMapper">  

   <!-- 根据id查询用户 -->

   <selectid="queryUserById"parameterType="int"resultType="user">

      select * from user where id=#{id}

   </select>

</mapper>

配置代理对象的bean组件

   <!-- 装配sql会话映射的接口,即委托对象的代理bean -->

   <beanclass="org.mybatis.spring.mapper.MapperFactoryBean">

      <propertyname="mapperInterface"value="com.mybatis.mapper.UserMapper"/>

      <propertyname="sqlSessionFactory"ref="sqlSessionFactory"/>

   </bean>

测试

   public void test1(){

      ApplicationContext ac=newClassPathXmlApplicationContext("applicationContext.xml");

      UserMapperuserMapper=ac.getBean(UserMapper.class);

      User user=userMapper.queryUserById(1)

      System.out.println(user);

   }

D.     关于配置dao接口代理对象bean组件的自动扫描

通过MapperScanConfigurer类开启委托对象的代理对象bean组件的自动扫描装载功能。

   <!-- 开启sql会话映射接口,代理bean的自动扫描

      扫描包中的接口的bean的id赋值为接口名首字母小写。

      sqlSessionFactory,也自动加载。不配置。

   -->

   <beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer">

      <propertyname="basePackage"value="com.mybatis.mapper"/>

   </bean>

这样可以扫描加载后,在业务流程中得到mapper的bean的id,直接使用bean。

在spring中开启代理对象bean组件的扫描后,可省去mybatis主配置文件中的扫描映射源的功能。

九、       逆向工程

使用官方网站的mapper自动生成工具mybatis-generator-core-1.3.2来生成po类和mapper映射文件。mybatis官方提供逆向工程,可以使用它通过数据库中的表来自动生成Mapper接口和映射文件(单表增删改查)和Po类。

步骤:

(一)            导入jar包

(二)            装配生成文件generatorConfig.xml

1.       配置数据库链接信息

Mysql版

<jdbcConnection

driverClass="com.mysql.jdbc.Driver"

         connectionURL="jdbc:mysql://localhost:3306/mybatis"

userId="root"

         password="admin">

      </jdbcConnection>

Oracle版

<jdbcConnection

driverClass="oracle.jdbc.OracleDriver"

         connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:oracle"

         userId="oracle"

         password="oooo">

</jdbcConnection>

2.       配置po类的目标文件包

<javaModelGeneratortargetPackage="com.***.***.po"

         targetProject=".\src">

         <!-- enableSubPackages:是否让schema作为包的后缀 -->

         <propertyname="enableSubPackages"value="false"/>

         <!-- 从数据库返回的值被清理前后的空格 -->

         <propertyname="trimStrings"value="true"/>

   </javaModelGenerator>

3.       配置mapper映射文件和接口的目标文件包

<sqlMapGeneratortargetPackage="com.***.***.dao"

         targetProject=".\src">

         <!-- enableSubPackages:是否让schema作为包的后缀 -->

         <propertyname="enableSubPackages"value="false"/>

   </sqlMapGenerator>

   <!-- targetPackage:mapper接口生成的位置 -->

   <javaClientGeneratortype="XMLMAPPER"

         targetPackage="com.***.***.dao"

         targetProject=".\src">

         <!-- enableSubPackages:是否让schema作为包的后缀 -->

         <propertyname="enableSubPackages"value="false"/>

   </javaClientGenerator>

4.       指定数据库表

Mysql版

<tabletableName="items"></table>

      <tabletableName="orders"></table>

      <tabletableName="orderdetail"></table>

      <tabletableName="user"></table>

Oracle版

<table schema=""tableName="sys_user"></table>

      <tableschema="" tableName="sys_role"></table>

      <tableschema="" tableName="sys_permission"></table>

      <tableschema="" tableName="sys_user_role"></table>

      <tableschema="" tableName="sys_role_permission"></table>    

      <!-- 有些表的字段需要指定java类型 -->

       <table schema=""tableName="">

       <columnOverride column=""javaType="" />

</table>

5.       完整版配置文件

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEgeneratorConfiguration

  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration1.0//EN"

  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">



<generatorConfiguration>

    <contextid="testTables"targetRuntime="MyBatis3">

        <commentGenerator>

            <!-- 是否去除自动生成的注释 true:是: false:否 -->

            <propertyname="suppressAllComments"value="true"/>

        </commentGenerator>

        <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->

        <jdbcConnectiondriverClass="com.mysql.jdbc.Driver"

            connectionURL="jdbc:mysql://localhost:3306/mybatis"userId="root"

            password="admin">

        </jdbcConnection>

        <!-- <jdbcConnectiondriverClass="oracle.jdbc.OracleDriver"

            connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"

            userId="yycg"

            password="yycg">

        </jdbcConnection> -->



        <!-- 默认false,把JDBC DECIMAL和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL和

            NUMERIC 类型解析为java.math.BigDecimal-->

        <javaTypeResolver>

            <propertyname="forceBigDecimals"value="false"/>

        </javaTypeResolver>



        <!-- targetProject:生成PO类的位置 -->

        <javaModelGeneratortargetPackage="com.***.***.pojo"

            targetProject=".\src">

            <!-- enableSubPackages:是否让schema作为包的后缀 -->

            <propertyname="enableSubPackages"value="false"/>

            <!-- 从数据库返回的值被清理前后的空格 -->

            <propertyname="trimStrings"value="true"/>

        </javaModelGenerator>

        <!-- targetProject:mapper映射文件生成的位置 -->

        <sqlMapGeneratortargetPackage="com.***.***.dao"

            targetProject=".\src">

            <!-- enableSubPackages:是否让schema作为包的后缀 -->

            <propertyname="enableSubPackages"value="false"/>

        </sqlMapGenerator>

        <!-- targetPackage:mapper接口生成的位置 -->

        <javaClientGeneratortype="XMLMAPPER"

            targetPackage="com.***.***.dao"

            targetProject=".\src">

            <!-- enableSubPackages:是否让schema作为包的后缀 -->

            <propertyname="enableSubPackages"value="false"/>

        </javaClientGenerator>

        <!-- 指定数据库表 -->

        <tabletableName="items"></table>

        <tabletableName="orders"></table>

        <tabletableName="orderdetail"></table>

        <tabletableName="user"></table>

        <!-- <table schema=""tableName="sys_user"></table>

        <table schema=""tableName="sys_role"></table>

        <table schema=""tableName="sys_permission"></table>

        <table schema=""tableName="sys_user_role"></table>

        <table schema=""tableName="sys_role_permission"></table> -->

       

        <!-- 有些表的字段需要指定java类型

         <table schema=""tableName="">

            <columnOverridecolumn="" javaType="" />

        </table> -->

    </context>

</generatorConfiguration>

注意:配置文件要放在工程目录下。也就是和src文件包同级的位置。

(三)            使用java类生成映射文件和po类文件

pubic class GeneratorSqlMap{

public void generator()throws Exception{

      List<String> warnings = newArrayList<String>();

      boolean overwrite =true;

      File configFile = new File("generatorConfig.xml");

      ConfigurationParser cp = newConfigurationParser(warnings);

      Configuration config =cp.parseConfiguration(configFile);

      DefaultShellCallback callback = newDefaultShellCallback(overwrite);

      MyBatisGenerator myBatisGenerator = newMyBatisGenerator(config,

            callback, warnings);

      myBatisGenerator.generate(null);

   }

   public static void main(String[] args)throws Exception {

      try {

         GeneratorSqlMap generatorSqlMap = new GeneratorSqlMap();

         generatorSqlMap.generator();

      } catch (Exception e) {

         e.printStackTrace();

      }

}

}

(四)            Copy使用生成的文件。注意前后复制时,文件目录名一致的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值