添加依赖

maven中Mybatis需要添加2个依赖:mybatis依赖数据库依赖(这里用mysql)

  • 还看到一种使用mybatis+mybatis-spring的方法来使用mybatis,后者是spring与mybatis的整合包,提供了一些新的注解,详见链接 ```xml org.mybatis mybatis 3.5.2

mysql mysql-connector-java 5.1.47

  1. <a name="ockzA"></a>
  2. # xml版
  3. <a name="C9QAh"></a>
  4. ## 编写MyBatis核心配置文件mybatis.xml
  5. ```xml
  6. <?xml version="1.0" encoding="UTF-8" ?>
  7. <!DOCTYPE configuration
  8. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  9. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  10. <configuration>
  11. <environments default="development">
  12. <environment id="development">
  13. <transactionManager type="JDBC"/>
  14. <dataSource type="POOLED">
  15. <property name="driver" value="com.mysql.jdbc.Driver"/>
  16. <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
  17. <property name="username" value="root"/>
  18. <property name="password" value="1234t"/>
  19. </dataSource>
  20. </environment>
  21. </environments>
  22. <mappers>
  23. <mapper resource="com/rao/dao/Mapper.xml"/>
  24. </mappers>
  25. </configuration>

<environment>为配置环境,可以有多个
<environments default="?">表示默认使用?这个配置环境。
<transactionManager>事务管理,默认使用JDBC
<dataSource>下为配置属性,参考JDBC
driver为数据库驱动程序
url:数据库地址
?后面为参数 useSSL=true表示安全连接 &amp是转义字符,表示
useUnicode=true表示使用Unicode编码以支持中文
characterEncoding=utf8表示使用utf8字符编码
username password然后是用户名和密码
<mappers><mapper resource="com/rao/dao/Mapper.xml"/></mappers>``设置使用哪个Mapper.xml
注意xml路径表示是**包/xml** 而类是**包.类**

创建Dao(数据/set/get)

public class User {

   private int id;  //id
   private String name;   //姓名
   private String pwd;   //密码

   //构造,有参,无参
   //set/get
   //toString()

}

创建Dao-Mapper接口

  • Mapper接口定义了操纵数据的一系列方法,这些方法各自对应一种SQL操作
  • **xxxMapper**是官方推荐命名。usermapper相当于userdao

    public interface UserMapper { 
      List<User> selectUser();
      String selectPassword(String id);   //id唯一姓名不一定唯一,所以用id查最好
      void createUser(int id,String name,String pwd);
      ...
    }
    

    创建Mapper.xml配置文件

  • 用于将sql语句与对应的dao-mapper接口联系在一起。可以看成dao-mapper.xml就是dao-mapper接口的实现类

  • idea不会编译src的java目录的xml文件 剧毒!解决方法见页面底。

  • sql操作标签:
  • > ... <写sql语句
  • id为对应的dao-mapper接口的方法
  • resultType为返回值类型,
    • 可以是自定义类类型,基本类,基本类型,List类型… 详见链接 方法返回值为void时就不写resultType参数
    • 单个map时:Map<String, Object>key时设置map,
    • 接收list时设置为T,
    • 返回多个map时:Map<String,Hotel>,resultType为Hotel
    • 注意resultType与dao-Mapper接口的方法返回值是有关联的

  • mybatis可以帮我们把对象序列化然后存储到数据库中,对象属性即是数据表的字段。(所以一个dao类就要新建一个mapper,这样就避免出现字段不一致的情况)
  • 同样的从数据库中取一条数据,mybatis也会自动反序列化为对象

    <?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接口所在的完整路径-->
    <mapper namespace="com.rao.testtemplate.mapper.StudentMapper">
    
    <select id="selectUser" resultType="com.rao.dao.User">  select * from user  </select>
    
    <insert id="batchInsert"   parameterType="java.util.List"  useGeneratedKeys="true" keyProperty="sid">
       <foreach collection="list" item="item" index="index" separator=";">
           insert into Student (sname,gender,classId)
           values(#{item.sname},#{item.gender},#{item.classId})
       </foreach>
    </insert>
    </mapper>
    
  • mapper接口传参如果是基本类且多个时,记得用@Param
  • namespace为xml文件对应的mapper接口的完整路径
  • id为sql对应的mapper方法名
  • resultType,resultMap为返回类型。前者是返回一个,后者是返回多个。对于增删改操作可以不设置,默认返回操作记录数
  • useGeneratedKeys为采用自增主键,keyProperty为主键名


Test

建立SQL连接

总之就一句话:sqlSessionFactory通过配置获取sqlSession(相当于数据库连接),然后sqlSession再拿Mapper对象然后执行

  • 每一个mybatis程序都是以一个SqlSessionFactory实例为核心的
  • SqlSessionFactorySqlSessionFactoryBuilder得到,SqlSessionFactory是用于构建SqlSession
  • SqlSession完全包含了所有面向数据库执行SQL 语句的方法,即相当于原来JDBC里的Statement

加载配置文件创建sql连接:这三句是死的,来源于官方文档

String resource = "mybatis-config.xml";  //加载mybatis配置文件
 InputStream inputStream = Resources.getResourceAsStream(resource);//根据配置信息建立连接
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

以上读取配置文件比较麻烦,所以我们将其封装为工具类工具类我们以后可以直接拿来用

public class MybatisUtil {

    private static SqlSessionFactory sqlSessionFactory;
//static代码块的内容在类启动的一开始就被加载

    static {
        try {//加载流对象注意异常
            String resource = "mybatis.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取SqlSession连接
    public static SqlSession getSession(){
        return sqlSessionFactory.openSession();  //开启/建立连接
    }

}
--------------------------------------------------------
    优化sql获取连接,实现自动提交事务

  public static SqlSession getSession(){
      return getSession(true); //事务自动提交
  }

  public static SqlSession getSession(boolean flag){
      return sqlSessionFactory.openSession(flag);
  }

调用接口方法执行SQL操作

  • 推荐第二种,第二种更加灵活
  • 方法一: SqlSession直接通过Mapper的方法方法获取结果
    • 方法1接收获取List不能直接接收List结果,需要通过selectList()
  • 方法二:SqlSession绑定具体Mapper接口,由Mapper接口去调用自身的sql操作方法获取结果
  • sqlSession用完记得关闭

public void test() {
//获取sqlSession连接
SqlSession session = MybatisUtil.getSession();

//执行sql语句
//方法一
List<User> users = session.selectList("com.rao.dao.UserMapper.selectUser");

//方法二
UserMapper mapper = session.getMapper(UserMapper.class);
    List<User> users = mapper.selectUser();
for (User user: users){  //foreach循环输出List,快捷键:users.for+enter
     System.out.println(user);
      }
       session.close();//关闭数据库连接
  }
}

静态资源不编译的解决方法

如果是静态资源未编译,其他正常,会报没有找到Mapper.xml
idea工程目录的target下是编译后的目录,解决前会看到编译目录下没有xml文件,解决后出现xml文件
idea默认不编译src下的xml文件。在pom.xml中添加一个这个即可

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
    </build>

导入约束问题

mapper.xml和核心配置文件mabits.xml中需要导入约束文件.dtd 所以最好复制已有的xml配置模板

注解版

  • mybatis最初配置信息是基于 XML ,映射语句(SQL)也是定义在 XML 中的。而到MyBatis 3提供了新的基于注解的配置。不幸的是,Java 注解的的表达力和灵活性十分有限。最强大的 MyBatis 映射并不能用注解来构建

  • 使用注解有一个xml功能不能替代,就是mybatis的映射功能,所以要保证字段与实体类同名

  • 使用注解和配置文件协同开发,才是MyBatis的最佳实践!
  • 利用注解开发的作用就是替代了mapper.xml映射文件,将sql的xml配置直接用注解形式写在对应的方法上(感觉更加直观一些)。而**mybatis.xml**还是推荐使用静态配置文件进行配置

sql注解主要分成 :

  • @select ()
  • @update ()
  • @Insert ()
  • @delete ()

    注解版Dao-mapper接口

    1、在我们的接口中添加注解
    该代码块有点问题,有些方法接收user对象,占位符应该是user.? 可能user.可以省略? ```java @Select(“select id,name,pwd password from user”)//相当于select * from user; public List getAllUser();

//添加一个用户 @Insert(“insert into user (id,name,pwd) values (#{user.id},#{user.name},#{user.pwd})”) int addUser(User user); 2、测试 User user = new User(6, “秦疆”, “123456”); mapper.addUser(user); session.close();

//修改一个用户 @Update(“update user set name=#{name},pwd=#{pwd} where id = #{id}”) int updateUser(User user); 2、测试 @Test User user = new User(6, “秦疆”, “zxcvbn”); mapper.updateUser(user); session.close(); }

//根据id删除一个用户 @Delete(“delete from user where id = #{id}”) int deleteUser(@Param(“id”)int id); 2、测试 mapper.deleteUser(6); session.close();

**2、在mybatis的核心配置文件中注入(之前是注入xml文件)**<br />`<mappers>`<br />`   <mapper class="com.kuang.mapper.UserMapper"/>`<br />`</mappers>`<br />**3、进行测试  还是跟以往一样**
```java
@Test
public void testGetAllUser() {
   SqlSession session = MybatisUtils.getSession();
   //本质上利用了jvm的动态代理机制
   UserMapper mapper = session.getMapper(UserMapper.class);
   List<User> users = mapper.getAllUser();
   for (User user : users){
       System.out.println(user);
  }
   session.close();
}
@Select("SELECT * FROM users LIMIT #{offset}, #{maxResults}")
List<User> getAll(@Param("offset") int offset, @Param("maxResults") int maxResults);

#与$的区别

  • #{} 的作用主要是替换预编译语句(PrepareStatement)中的占位符? 【推荐使用】
  • 而${}是字符串替换,所以使用$替换时如果是字符串参数必须额外传入引号,否则语法错误,拼接出的sql字符串没有引号
  • 任何时候都应该优先使用#{},$可能造成sql注入安全问题,另外$可能造成一些语法错误,如下
    • {}可以避免sql注入,本质是因为mybatis在底层实现了预编译。预编译的实现是jdbc的PreparedStatement,被该类预编译的sql语句不允许被修改

      ```java String sql = “update ft_proposal set id = ?” PreparedStatement ps = conn.preparedStatement(sql); ps.setString(1,”2”); //第一个问号替换为参数 ps.executeUpdate();

//注意不要错误使用,比如传入的需要预编译的sql已经被注入 String sql = “update ft_proposal set id = “+id; //id:3;drop table ft_proposal; PreparedStatement prepareStatement = conn.prepareStatement(sql); //这时已经sql注入了


- sql中的占位变量与方法参数同名时不加@Param可以。不同名时必须使用@Param
```sql
select * from ${tableName} where name = #{name}
假如表名是user; delete user; --     则解析后变为
select * from user; delete user; -- where name = ?;
则--后认为是注释,则造成sql先执行了select * from user;    随后执行了delete user;

猜测:使用#{}  在sql编译期间就不会出现上述歧义,执行时才会进行替换  在sql看来  user; delete user;   是一个整体不会出现这种歧义   

同时对于一些传入值特殊时#也会更有用,如传入""   $则编译为in()  报错       而#会编译为in(null) 不报错

#对于字符串会自动添加引号  而$不会,容易造成错误

线程安全问题

  • SqlSession 接口有 3 个实现类:
    • 1 DefaultSqlSession。非线程安全
    • 2 SqlSessionManager 非线程安全
    • 3 SqlSessionTemplate(线程安全,但是在 mybatis-spring 包中)
  • 因此,SqlSession 不应该是单例的,于此同时,依赖于 session 的 Mapper 要么也应该是多例的,要么就要用上 ThreadLocal !
    • 或者SqlSession的作用域应该仅仅为请求或者方法中。执行完请求/方法立刻关闭