snorql を始める
- この投稿から何を期待できますか?
- ツールを理解する
- Dropwizard
- Kotlin
- Maven - ローカルマシンのセットアップ
- アプリケーションのセットアップ
-新しいプロジェクトの作成
-依存関係の追加
-ビルドとコンパイル
-プロジェクト構造
-コード - アプリケーションの構築と実行
- 次のステップ
- よくある質問
そうですね、ウダーンでも状況はそれほど変わりませんでした。そこで私たちの何人かが問題を自分たちの手で解決し、これらの問題に先制的に取り組むのに役立つツールを作成することにしました。
入力 …
シュノーケルとは何ですか?
snorql は、SQL メトリクスを使用してデータベース関連の問題を監視および診断することを目的として Udaan で開発されたオープンソース プロジェクトです。
すべてのデータベースのパフォーマンスを可視化できるため、推測ゲームをやめてデータベースの最適化を簡単に開始できます。そして、言っておきますが、この可視性の向上は、私たちの組織にとって大きな変革をもたらしました。これにより、すべてのチームの説明責任が強化されました。
結果がすべてを物語っています。snorql のおかげで、
- 50 を超えるデータベース全体でパフォーマンスの向上が確認されています。
- クラウド コストを 60% 以上削減しました。
- 開発者の生産性の向上
- デバッグ時間の短縮
私の前置きがあなたの興奮を刺激し、すぐに始めたいと思っているなら、ここは正しい場所です。ただし、さらに説得力が必要な場合は、 「 snorql — diagnosing Databases like a Boss 」というタイトルの素晴らしい記事を必ずチェックしてください。
この投稿から何を期待できますか?
Snorql は、アクティブなクエリ、ブロックされたクエリ、インデックス統計、データベースの増加などの複数のメトリクスを公開します。完全なリストはここにあります。この記事では、アクティブなクエリを取り上げます。Active Queries は、クエリのパフォーマンスをリアルタイムで監視して最適化する必要がある SQL Server ユーザーにとって貴重なツールです。
snorqlこの投稿では、単純な Kotlin Dropwizard アプリケーションに統合する方法を説明します(他の Java フレームワークでも同じことを複製できます)。このチュートリアルの最後では、アプリケーションは RESTful API を公開します。これを使用すると、特定のデータベースのライブ クエリ統計を見つけることができます。
ツールを知る
Kotlin、Dropwizard、Maven にすでに慣れている方は、このセクションを飛ばしていただいても構いません。
ドロップウィザード
Dropwizard は、RESTful Web サービスを構築するための軽量の Java フレームワークです。Dropwizard は、Jersey、Jackson、JDBI などの安定したライブラリを軽量パッケージにまとめます。詳細については、こちらをご覧くださいhttps://www.dropwizard.io/en/latest/。
興味深い事実: Dropwizard は、Ruby プログラミング言語で人気のある Web アプリケーション フレームワークである Ruby on Rails からインスピレーションを受けています。Dropwizard の作成者は、Java エコシステムに同じレベルの生産性と使いやすさをもたらしたいと考えていました。
コトリン
Kotlin は、ロシアに本拠を置くソフトウェア開発会社 JetBrains によって作成された関数型およびオブジェクト指向プログラミングをサポートするプログラミング言語です。Kotlin の構文と概念は、C#、Scala、Java に似ています。詳細については、こちらをご覧くださいhttps://kotlinlang.org/
Kotlin に関する興味深い事実の 1 つは、その名前が実際にはロシアのサンクトペテルブルク近くの Kotlin 島と呼ばれる島に由来しているということです。Kotlin の作成者がこの名前を選んだのは、Kotlin の作成者の多くがサンクトペテルブルクまたはその周辺に住んでおり、この島がその地域の有名なランドマークであるためです。
メイビン
Maven は、Java 用のビルド自動化および管理ツールです。Maven を使用すると、ソフトウェアの構築と依存関係を簡単に定義できます。
興味深い事実: Maven は、2002 年にシカゴのオヘア空港で飛行機を待っているときに Jason van Zyl によって作成されました。
ローカルマシンのセットアップ
同じことに関する記事や YouTube ビデオがたくさんありますが、いくつかのクイックリファレンスを添付しました。
- Maven のインストールとセットアップ —https://www.freecodecamp.org/news/how-to-get-started-with-maven-36851d8cfd96/
- Kotlin のインストール —https://www.oreilly.com/library/view/kotlin-cookbook/9781492046660/ch01.html
- IntelliJ のインストール —https://www.jetbrains.com/help/idea/installation-guide.html
このセクションでは、Maven、Kotlin、IntelliJ (または Maven プロジェクトをサポートするその他の IDE) がすでにセットアップされていることを前提としています。
新しいプロジェクトの作成
- 「ファイル」→「新規」→「プロジェクト」→「Maven」をクリックします。次のポップアップが表示されます
3. IDE は、次の構造を持つプロジェクトを含む pom.xml ファイルを開きます。
依存関係の追加
実装を開始する前に、プロジェクトに必要な特定の依存関係をファイルに追加する必要がありますpom.xml。一緒にやりましょう。
まず、プロパティ タグで Kotlin と Dropwizard のバージョンを定義します。
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<kotlin.version>1.4.10</kotlin.version>
<kotlin.compiler.languageVersion>1.4</kotlin.compiler.languageVersion>
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
<dropwizard.version>2.0.13</dropwizard.version>
</properties>
<dependencies>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-core</artifactId>
<version>${dropwizard.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
jdbi3
データベースに接続するには、この依存関係が必要になります。ここではjdbi3を使用しています。これは、JDBC/JDBI のどのバージョンでも機能します。
プロパティ:
<jdbi.version>3.37.1</jdbi.version>
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-core</artifactId>
<version>${jdbi.version}</version>
</dependency>
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-sqlobject</artifactId>
<version>${jdbi.version}</version>
</dependency>
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-kotlin-sqlobject</artifactId>
<version>${jdbi.version}</version>
</dependency>
アプリケーションが SQL サーバー データベースに正常に接続できるようにするには、これを追加する必要があります。これを省略すると、悪名高い例外が発生しますjava.sql.SQLException: No suitable driver found。ここでは、SQL サーバーに対応する事前定義されたメトリクスを提供するモジュールを使用するためsnorql-extensions、このドライバーを使用します。
snorql-framework基礎となるツールの基本フレームワークである別のモジュールが存在します。今後の記事でこのフレームワークを Postgres、MySQL などのさまざまなデータベースに活用する方法を説明する予定です。
プロパティ:
<mssql.version>9.2.1.jre8</mssql.version>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>${mssql.version}</version>
</dependency>
うーん、これは外せませんね!
プロパティ:
<snorql.version>0.5.6</snorql.version>
<dependency>
<groupId>com.udaan.snorql</groupId>
<artifactId>snorql-extensions</artifactId>
<version>${snorql.version}</version>
</dependency>
ビルドとコンパイル
次のステップでは、ソースコードをコンパイルするために、<sourceDirectory>と のソース ディレクトリを指定します。<testSourceDirectory>ソース コードをコンパイルするために必要な Kotlin プラグインも構成します。
pom.xml依存関係セクションの後に示されているようにコードを追加します。
<dependencies>
.....
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
これを実行するとすぐに、kotlin が赤で強調表示されているのが表示されます。これは、現時点ではパスが存在しないためです。次のセクション→プロジェクト構造に進みます。
プロジェクトの構造
これが私のプロジェクト構造です。最初は同じものを使用し、後で要件に応じてカスタマイズできます。
コード
ステップ 1:まず、config.yml内にファイルを作成しますsrc/main/resources。この設定ファイルでパラメータを定義すると、設定クラスのインスタンスに逆シリアル化されます。少なくとも 1 つのパラメータを追加する必要があります。追加しない場合、Dropwizard フレームワークはコンパイル中にエラーをスローします。先に進み、これを追加しましょう:
environment: local
package com.hawkeye.configuration
import com.fasterxml.jackson.annotation.JsonProperty
import io.dropwizard.Configuration
class AppConfig(@JsonProperty("environment") val environment: String): Configuration()
ステップ 4:BootstrapSnorqlApplication次に、パス内に .kt ファイルを作成しsrc/main/kotlin/com/hawkeye、次のコードを追加します。
package com.hawkeye.core
import org.jdbi.v3.core.Jdbi
import org.jdbi.v3.core.kotlin.KotlinPlugin
import org.jdbi.v3.sqlobject.SqlObjectPlugin
import org.jdbi.v3.sqlobject.kotlin.KotlinSqlObjectPlugin
class JdbiFactory {
/**
* Return instance of JDBI with all plugins installed
* @param dbName Name of the DB to connect
*/
fun getInstance(dbName: String): Jdbi {
return Jdbi.create(getConnectionStringByDatabaseName(dbName))
.installPlugin(SqlObjectPlugin())
.installPlugin(KotlinPlugin())
.installPlugin(KotlinSqlObjectPlugin())
}
private fun getConnectionStringByDatabaseName(dbName: String): String {
return when(dbName) {
"db-prod" -> "jdbc:sqlserver://<server-name>:<port>;database=$dbName;user=<username>;password=<pwd>;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;"
else -> ""
}
}
}
ステップ 5:Connection次に、公開するインターフェイスを実装する必要がありますsnorql-framework。これを呼び出してみましょうSqlServerConnection。ユーザーのデータベースと対話するために必要なメソッドが保持されますsnorql。この記事では、このrun()メソッドのみを実装するだけで十分です。他の詳細については、別の詳細なブログ投稿で説明します。
SqlServerConnection.ktパスにファイルを作成しsrc/main/kotlin/com/hawkeye/core、以下のコードを追加します。
package com.hawkeye.core
import com.udaan.snorql.framework.metric.Connection
import com.udaan.snorql.framework.models.HistoricalDatabaseResult
import javax.inject.Inject
class SqlServerConnection @Inject constructor(private val jdbi3Factory: JdbiFactory) : Connection {
override fun <T> run(databaseName:String, query: String, mapClass: Class<T>,params: Map<String, *>): List<T> {
return if(params.isNotEmpty()){
jdbi3Factory.getInstance(databaseName).withHandle<List<T>, Exception> { handle ->
handle.createQuery(query).bindMap(params).mapTo(mapClass).toList()
}
} else{
jdbi3Factory.getInstance(databaseName).withHandle<List<T>, Exception> { handle ->
handle.createQuery(query).mapTo(mapClass).toList() as List<T>
}
}
}
override fun storeData(storageBucketId: String, columns: List<String>, rows: List<List<Any>>) {
TODO("Not yet implemented")
}
override fun getHistoricalData(
storageBucketId: String,
metricId: String,
databaseName: String,
columns: List<String>,
paginationParams: Map<String, *>,
params: Map<String, *>
): HistoricalDatabaseResult {
TODO("Not yet implemented")
}
}
snorql は、アプリケーションに統合して使用できる多くの便利な SQL メトリクスを公開します。この投稿では、データベースを使用したことのある人にとって最も関連性の高い指標を選択しますActive Queries。
アクティブ クエリ (ライブ クエリ統計とも呼ばれる) は、ユーザーがクエリの進行状況をリアルタイムで監視できるようにする SQL Server の機能です。これは、完了率、経過時間、推定残り時間などのクエリのステータスに関する情報と、SQL Server がクエリを処理するために使用する実行プランを提供します。
そのためには、SnorqlMetricsResource.kt中にファイルを作成しsrc/main/kotlin/com/hawkeye/resources、以下のコードを追加します。
package com.hawkeye.resources
import com.fasterxml.jackson.annotation.JsonProperty
import com.udaan.snorql.extensions.performance.PerformanceEnums
import com.udaan.snorql.extensions.performance.models.ActiveQueryInput
import com.udaan.snorql.extensions.performance.models.ActiveQueryResult
import com.udaan.snorql.framework.metric.SqlMetricManager
import com.udaan.snorql.framework.models.IMetricRecommendation
import com.udaan.snorql.framework.models.MetricPeriod
import javax.ws.rs.Consumes
import javax.ws.rs.POST
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.container.AsyncResponse
import javax.ws.rs.container.Suspended
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
@Path("/snorql")
class SnorqlMetricsResource {
/*
* Fetches list of active-queries metric for a [activeQueryMetricInput]
*/
@POST
@Path("activeQueries")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
fun getActiveQueryMetric(
input: Input,
@Suspended asyncResponse: AsyncResponse
) {
val activeQueryInput = ActiveQueryInput(
databaseName = input.databaseName,
metricPeriod = input.metricPeriod,
metricId = input.metricId
)
try {
val response = SqlMetricManager.getMetric<ActiveQueryInput, ActiveQueryResult, IMetricRecommendation>(
PerformanceEnums.ACTIVE_QUERIES.getId(),
activeQueryInput
)
asyncResponse.resume(Response.ok(response).build())
} catch (e: Exception) {
println("Something went wrong. Error : ${e.message as String}")
Response.status(500).entity(e.message as String).build()
}
}
}
data class Input (
@JsonProperty("metricId")
val metricId: String = PerformanceEnums.ACTIVE_QUERIES.getId(),
@JsonProperty("metricPeriod")
val metricPeriod: MetricPeriod,
@JsonProperty("databaseName")
val databaseName: String
)
package com.hawkeye
import com.google.inject.AbstractModule
import com.google.inject.Guice
import com.hawkeye.configuration.AppConfig
import com.hawkeye.core.SqlServerConnection
import com.hawkeye.resources.SnorqlMetricsResource
import com.udaan.snorql.extensions.SQLCommonMetrics
import com.udaan.snorql.framework.metric.SqlMetricManager
import io.dropwizard.Application
import io.dropwizard.setup.Environment
class HawkeyeApplication: Application<AppConfig>() {
companion object {
@JvmStatic fun main(args: Array<String>) = HawkeyeApplication().run(*args)
}
override fun run(appConfig: AppConfig, environment: Environment) {
environment.jersey().register(SnorqlMetricsResource::class.java)
registerSQLMetrics()
}
private fun registerSQLMetrics() {
val sqlServerConnectionInstance =
Guice.createInjector(SqlClientModule()).getInstance(SqlServerConnection::class.java)
SqlMetricManager.setConnection(sqlServerConnectionInstance)
SQLCommonMetrics.initialize()
}
}
class SqlClientModule : AbstractModule()
アプリケーションの構築と実行
実行する準備ができていますHawkeyeApplication
これを行うには、以下に示すように構成を追加します。
server src/main/resources/config.ymlプログラム引数を追加していることに注目してください。これにより、Dropwizard アプリがサーバーとして、指定された構成ファイルの場所に対して実行されるように指示されます。
すべてがうまくいけば、ターミナルに次のようなものが表示されるはずです。そうでなくて、いくつかのエラーで怒鳴られたとしても、私がそれもカバーしますので、心配しないでください。FAQ セクションに移動し、私が直面したエラーと解決策を確認してください。
Postman または他の同様のツールに移動し、API をテストします。[インポート] -> [生のテキスト] -> 以下のカール呼び出しをコピー&ペースト -> [続行] をクリック -> [送信] をクリックします。
curl --location --request POST 'localhost:8080/snorql/activeQueries' \
--header 'Content-Type: application/json' \
--data-raw '{
"databaseName": "db-prod",
"metricId": "performance_activeQueries",
"metricPeriod": "REAL_TIME",
"recommendationRequired": true
}'
ここでは、データベースに対するすべてのアクティブなクエリを確認するためにクエリを実行しましたdb-prod。応答は 3 つの部分に分かれています。
メトリック入力
これにより、ユーザーが指定した入力が、オプションのフィールドにデフォルト値とともに返されます。
"metricInput": {
"from": null,
"to": null,
"recommendationRequired": false,
"metricId": "performance_activeQueries",
"metricPeriod": "REAL_TIME",
"databaseName": "db-prod"
}
これにより、データベース内で現在実行されているクエリのリストと、それらに関連付けられたすべての関連パラメータが表示されます。これは次のシナリオで役立つ可能性があります。
- データベースのレイテンシの増加をデバッグしようとしており、CPU を大量に消費している長時間実行クエリがあるかどうかを確認したい場合は、 を参照してください
elapsedTime。このような長時間実行クエリは、非効率なクエリ プラン、最適ではないインデックス作成、クエリの作成が不十分であるなど、さまざまな問題によって発生する可能性があります。これに加えて、これを使用してデータベース全体のクエリ実行時間の分布を分析し、問題が発生する前に予防的な措置を講じることもできます。 - データベースがハングしているように見える場合、またはプロセスが進行していない状態の場合、データベースのブロックを確認することは非常に意味があり、 を使用すると、このクエリをブロックしている正確な sessionId を把握できます
blockedBy。 - この
openTransactionCountパラメータは、データベース内で開いているトランザクションの数を常に監視するために使用されます。この数が一貫して高い場合は、適時にコミットまたはロールバックされていないトランザクションがあることを示している可能性があります。これにより、リソースの競合、ロックの増加、デッドロックなどの問題が発生する可能性があり、データベースのパフォーマンスや可用性に悪影響を与える可能性があります。このパラメーターをクエリ実行時間やクエリ待機時間などの他のパフォーマンス メトリックと組み合わせて使用することでopenTransactionCount、注意が必要なクエリを正確に特定できます。
"metricOutput": {
"result": {
"queryList": [
{
"sessionId": 627,
"status": "running",
"blockedBy": 0,
"waitType": null,
"waitResource": "",
"percentComplete": 0,
"waitTime": "00:00:00",
"cpuTime": 2,
"logicalReads": 19,
"reads": 0,
"writes": 0,
"elapsedTime": "0d 00:00:00",
"queryText": "<?query -- \\n\\nSELECT DISTINCT ffi.shipment_group_id, so.extra_data, so.order_type, cac.amount_in_paisa as consumed_amount_in_paisa FROM fulfillment_line_items ffi JOIN seller_order_line ol on ol.order_line_id = ffi.order_line_id JOIN seller_order so on so.order_id = ol.seller_order_id LEFT OUTER JOIN collected_advance_consumable cac on cac.consumed_for = ffi.shipment_group_id WHERE ffi.shipment_group_id in (@P0)\\n\\n--?>",
"storedProc": "",
"command": "SELECT",
"loginName": "udaan",
"hostName": "order-processing-daemons-6fdfb74677-86xtx",
"programName": "order-processing-daemons-6fdfb74677-86xtx/order-mgmt",
"hostProcessId": 0,
"lastRequestEndTime": "2023-02-24 10:36:18.283",
"loginTime": "2023-02-24 10:32:52.12",
"openTransactionCount": 0
}
]
},
"recommendation": null
}
このセクションでは、上記の出力を生成するために snorql によって使用されるクエリについて詳しく説明します。これには、Microsoft の公式ドキュメントへの簡単な説明とクイック リファレンスも含まれています。
&supportsHistoricalはminimumRepeatInterval、snorql がクエリ出力の結果セットを一定の間隔で記録および保存して、過去のデータを再確認できるようにする機能の一部です。これは事後分析、問題の優先順位付け、異常の発見に役立ちます。この機能には、それ自体の詳細な投稿が別途必要になります。
"metadata": {
"underlyingQueries": [
"SELECT sessionId=s.session_id\\n ,status=r.STATUS\\n ,blockedBy=r.blocking_session_id\\n ,waitType=r.wait_type\\n, waitResource=r.wait_resource\\n, waitTime=CONVERT(VARCHAR, DATEADD(ms, r.wait_time, 0), 8)\\n, cpuTime=r.cpu_time\\n, logicalReads=r.logical_reads\\n, r.reads\\n ,r.writes,\\n r.percent_complete as percentComplete\\n,elapsedTime=CONVERT(varchar, (r.total_elapsed_time/1000 / 86400))+ 'd ' +\\n CONVERT(VARCHAR, DATEADD(ms, r.total_elapsed_time, 0), 8)\\n ,queryText=CAST((\\n '<?query -- ' + CHAR(13) + CHAR(13) + Substring(st.TEXT, (r.statement_start_offset / 2) + 1, (\\n (\\n CASE r.statement_end_offset\\n WHEN - 1\\n THEN Datalength(st.TEXT)\\n ELSE r.statement_end_offset\\n END - r.statement_start_offset\\n) / 2\\n) + 1) + CHAR(13) + CHAR(13) + '--?>'\\n ) AS XML)\\n, storedProc=COALESCE(\\n QUOTENAME(DB_NAME(st.dbid)) + N'.' + \\n QUOTENAME(OBJECT_SCHEMA_NAME(st.objectid, st.dbid)) + N'.' +\\n QUOTENAME(OBJECT_NAME(st.objectid, st.dbid)), ''\\n)\\n --,qp.query_plan AS 'xml_plan' -- uncomment (1) if you want to see plan\\n, r.command\\n ,loginName=s.login_name\\n ,hostName=s.host_name\\n ,programName=s.program_name\\n ,hostProcessId=s.host_process_id\\n ,lastRequestEndTime=s.last_request_end_time\\n ,loginTime=s.login_time\\n ,openTransactionCount=r.open_transaction_count\\n FROM sys.dm_exec_sessions AS s\\n INNER JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id\\n CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st\\n --OUTER APPLY sys.dm_exec_query_plan(r.plan_handle) AS qp -- uncomment (2) if you want to see plan \\n ORDER BY r.blocking_session_id"
],
"referenceDocumentation": [],
"description": "",
"supportsHistorical": true,
"minimumRepeatInterval": "10"
}
コード全体をチェックアウトしたい場合は、ここにアクセスしてください。https://github.com/lakshmi-udaan/hawkeye
次のステップ
我々のしたこと?
必要なデータを取得したので、強力な視覚化ツールの作成に着手しました。この目的を達成するために、ユーザーフレンドリーな UI レイヤーで API を強化し、すべてのデータベースの包括的な鳥瞰図と個々のデータベースの詳細で粒度の高いビューの両方を提供する SQL ダッシュボードを作成しました。私たちの組織の開発者は、SQL 関連のタスクでこれに大きく依存しています。残念ながら、現時点ではオープンソースではありませんが、ご興味がございましたら、喜んで詳しくお話しさせていただきます。ここに同じもののスニークピークがあります。
何ができるでしょうか?
snorql の使用方法がわかったので、その可能性を最大限に引き出し、データベースのパフォーマンスを飛躍的に向上させるのは時間の問題です。
利用可能なすべての指標のリストは、ここで見つけることができます。これらのメトリクスは、ここでSqlMetricManager.getMetric()アクティブ クエリの API エンドポイントを作成したときに行ったように、内部で渡されるパラメーターを変更するだけで取得できます。
次回の投稿では、これらの指標のいくつかを使用してデータベースの生産性を 10 倍に高める方法について詳しく説明します。
読んでくれてありがとう!
よくある質問
- xyz でアーティファクト com.udaan.snorql:snorql-framework:pom:0.5.6 が見つかりませんでした。
解決策: を実行しますmvn clean install。これにより、以前のビルドで作成されたものはすべてクリーンアップされ、プロジェクトをビルドしてローカル Maven リポジトリ (.m2\repository) に jar が追加されます。 - このエラーが表示された場合は、 解決策: をロードする必要があります。追加を見逃しています
java.sql.SQLException: No suitable driver foundjdbc drivermssql-jdbc
https://udaan-com.github.io/snorql/
https:///engineering-udaan/snorql-diagnosing-databases-like-a-boss-54f2e8fbf57a

![とにかく、リンクリストとは何ですか?[パート1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































