在pom.xml中,添加mybatis依賴,mysql-jdbc依賴,把編譯版本改成1.8
你問,爲啥mybatis不會自動依賴mysql-jdbc,須要手動寫明?答:由於mysql驅動是經過字符串動態加載的,這是一種「動態依賴」,Maven只能推導出「靜態依賴」。「動態依賴」是一種更加靈活的依賴。html
Maven默認的Java版本是1.6,沒法使用lambda表達式(1.8)和鑽石運算符(1.7)。java
代碼片斷:pom.xmlmysql
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>wyf</groupId> <artifactId>xqweb</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.4</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf8</encoding> </configuration> </plugin> </plugins> </build> </project>
建立好了pom.xml,就能夠開始編碼了。最終的目錄結構以下,下面讓咱們來一步一步建立文件。
web
代碼片斷:mybatis.xmlspring
<?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> <properties resource="config.properties"> </properties> <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 class="haha.UserDao"/> <mapper resource="user.xml"/> </mappers> </configuration>
代碼片斷:config.propertiessql
username=root password=haha driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai
把配置信息跟mybatis.xml分開的好處是:更清晰。mybatis屬於代碼區,config.properties改起來比較簡單。數據庫
User有三個屬性:name,age和id,重寫toString()方法便於調試。apache
package haha; public class User { String name; Integer age; Integer id; public User(){} public User(String name,int age){ this.name=name; this.age=age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Override public String toString() { return String.format("(id:%d,name:%s,age:%d)", id, name, age); } }
相應的,在數據庫中創建一個表userapi
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(10) DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=119 DEFAULT CHARSET=utf8mb4
UserDao接口有兩個功能:插入、查詢所有。數組
package haha; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.SelectKey; import java.util.List; public interface UserDao { @Insert("insert into user(name,age) value(#{name},#{age})") int insert_withoutPrimaryKey(@Param("name") String name, @Param("age") int age); int insert_useGeneratedKey(@Param("user") User user); int insert_selectKey(@Param("user") User user); @Insert("insert into user(name,age) value(#{user.name},#{user.age})") @SelectKey(statement = "select last_insert_id()", keyProperty = "user.id", before = false, resultType = int.class) int insert_selectKeyAnotation(@Param("user") User user); @Select("select*from user") List<User> getAll(); }
Mybatis寫SQL語句有兩種方式:一、使用註解;二、使用xml
對於比較長的SQL語句放在xml中,對於比較短的SQL語句放在註解中
在上面定義的UserDao中,insert_userGeneratedKey()和insert_selectKey()兩個函數沒有給出對應的SQL語句,須要在xml文件中進行定義。
代碼片斷:user.xml
<?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="haha.UserDao"> <insert id="insert_useGeneratedKey" parameterType="haha.User" useGeneratedKeys="true" keyProperty="user.id"> insert into user set id=#{user.id},name=#{user.name},age=#{user.age} </insert> <insert id="insert_selectKey" parameterType="haha.User"> <selectKey keyProperty="user.id" keyColumn="id" order="AFTER" resultType="int"> SELECT last_insert_id() </selectKey> insert into user(name,age) VALUE (#{user.name},#{user.age}) </insert> </mapper>
編寫一個UserService類測試一下
package haha; 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; import java.util.List; public class UserService { public static void main(String[] args) throws IOException { String resource = "mybatis.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(inputStream); SqlSession session = factory.openSession(); UserDao dao = session.getMapper(UserDao.class); //使用默認主鍵 int affectedRows = dao.insert_withoutPrimaryKey("張三", 25); System.out.println(affectedRows); //使用useGeneratedKey,將主鍵注入到user.id中 User u = new User("張三", 17); affectedRows = dao.insert_useGeneratedKey(u); System.out.println(affectedRows + " " + u.getId()); //使用selectKey執行在插入以前或以後執行查詢語句 affectedRows = dao.insert_selectKey(u); System.out.println(affectedRows + " " + u.getId()); //使用selectKey註解的方式 affectedRows = dao.insert_selectKeyAnotation(u); System.out.println(affectedRows + " " + u.getId()); session.commit(); List<User> a = dao.getAll(); a.forEach(System.out::println); } }
以下代碼,insert()函數的返回值爲int類型,表示affectedRows,即受影響的行數,若是成功插入返回1,若是不成功插入,返回0。對於一切寫操做(insert,update,delete),返回值都是affectedRows。
@Insert("insert into user(name,age) value(#{name},#{age})") int insert(@Param("name") String name, @Param("age") int age);
@SelectKey
關於insert()有一種需求很常見:如何肯定插入數據的主鍵。對於MySQL中的自增類型主鍵,無需提供主鍵能夠直接插入。仍是以insert()函數爲例,這個SQL語句沒有提供主鍵,主鍵是自增類型能夠自動生成。
@Insert("insert into user(name,age) value(#{name},#{age})") int insert(@Param("name") String name, @Param("age") int age);
下面介紹一個重要註解@SelctKey(statement="SQL語句",keyProperty="將SQL語句查詢結果存放到keyProperty中去",before="true表示先查詢再插入,false反之",resultType=int.class)
其中:
注意:
<selectKey>
的標籤@Insert
, @InsertProvider
, @Update
or @UpdateProvider
搭配使用。在其餘方法上將被忽略。@SelectKey
註解,而後Mybatis將忽略任何生成的key屬性經過設置@Options
,或者配置屬性。當before=true,能夠經過SQL語句來填充insert語句中的某個參數,這個參數的名稱能夠經過keyProperty來指明。
@Insert("insert into user value(#{id},#{name},#{age})") @SelectKey(statement="select count(1)from user", keyProperty="id", before=true, resultType=int.class) int insert(@Param("name") String name, @Param("age") int age);
這個函數返回值是affectedRows,也就是插入成功返回1,插入失敗返回0。
以上這段代碼有一個大大的隱患,萬萬不能用在生產環境中。這個隱患就是:不能經過count()來肯定id,多線程狀況下有可能產生衝突。解決方案:可使用UUID做爲主鍵。
注意keyProperty不能使基本類型,由於那樣賦值以後就找不到了(至關於傳值)
註解的方式
@Insert("insert into user(name,age) value(#{user.name},#{user.age})") @SelectKey(statement = "select last_insert_id()", keyProperty = "user.id", before = false, resultType = int.class) int insert_selectKeyAnotation(@Param("user") User user);
XML的方式
<insert id="insert_selectKey" parameterType="haha.User"> <selectKey keyProperty="user.id" keyColumn="id" order="AFTER" resultType="int"> SELECT last_insert_id() </selectKey> insert into user(name,age) VALUE (#{user.name},#{user.age}) </insert>
DUAL表是Oracle中的神奇的表
使用序列做爲主鍵
<insert id="insertSelective" parameterType="com.zehin.vpaas.base.domain.SfyHazardAnalysis"> <selectKey resultType="java.lang.Integer" order="BEFORE" keyProperty="hazardId"> SELECT SEQUENCE_1.NEXTVAL FROM DUAL </selectKey> insert into SFY_HAZARD_ANALYSIS <trim prefix="(" suffix=")" suffixOverrides=","> HAZARD_ID, <if test="hazardTime != null"> HAZARD_TIME,</if> <if test="hazardTitle != null"> HAZARD_TITLE, </if> <if test="hazardMeasure != null"> HAZARD_MEASURE, </if> <if test="buildId != null"> BUILD_ID, </if> </trim> <trim prefix=" values(" suffix=")" suffixOverrides=","> #{hazardId,jdbcType=INTEGER}, <if test="hazardTime != null">#{hazardTime,jdbcType=VARCHAR},</if> <if test="hazardTitle != null"> #{hazardTitle,jdbcType=VARCHAR}, </if> <if test="hazardMeasure != null"> #{hazardMeasure,jdbcType=VARCHAR}, </if> <if test="buildId != null"> #{buildId,jdbcType= INTEGER}, </if> </trim> lt;/insert>
使用GUID做爲主鍵
<insert id="insertUser" parameterType="com.danny.mybatis.po.User"> <selectKey keyProperty="userId" order="BEFORE" resultType="java.lang.Integer"> select SYS_GUID() as userId from DUAL </selectKey> insert into T_USER(userId,userName,birthday,sex,address) values (#{userId},#{userName},#{birthday},#{sex},#{address}) </insert>
<insert id="insert" parameterType="Spares" useGeneratedKeys="true" keyProperty="id"> insert into spares(spares_id,spares_name, spares_type_id,spares_spec) values(#{id},#{name},#{typeId},#{spec}) </insert>
<insert id="insertUser" useGeneratedKeys="true" keyColumn="id"> insert into user(name,age) VALUE (#{name},#{age}) </insert>
除了使用selectKey的方式獲取剛剛插入數據的主鍵,還有如下方案:
一、若是是MySQL,能夠用select last_insert_id()
語句獲取新插入數據的主鍵。
二、若是主鍵類型是UUID,能夠直接在代碼中生成主鍵進行插入,這樣就不須要從數據庫中讀取主鍵了,主動權掌握在代碼手中。