how to start a sql server agent job from java code - java

I have few SQL Server Agent Jobs running in my project. The jobs run perfectly as scheduled, no issues.
But now I need to be able to start these jobs from the front end (Like on a click of button or so).
How can I do it ?
Do these jobs behave just like a functions ?

You can do this with any db connector I've tried--here are a couple examples...
Using CallableStatement:
Connection rConn = //however you get your connection...
CallableStatement cs = rConn.prepareCall("EXEC dbo.sp_start_job N'your job name'");
boolean checkvar = cs.execute();
Alternatively, if you use a jdbc template:
jdbcTemp = //however you get your template...
jdbcTemp.update("EXEC msdb.dbo.sp_start_job N'" + procName + "'");
Also, you will likely need to adjust the permissions of the msdb in order for this to work. Your account needs to either be a sysadmin or have the SQLAgentOperatorRole role. To set this in SQL Server Management, go to Security under your db engine, expand logins, right click on the account you will use and select properties. Under Server Roles you can grant sysadmin, or under User Mapping check msdb, then select TargetServersRole and SQLAgentOperatorRole from the list below.
hth

you can call it by using the sp_startjob proc
example
EXEC msdb.dbo.sp_start_job N'MyJobName';

Related

Stop, restore and restart MS SQL server

I have a build deployed on my local and I am able to access the application using https://localhost:8443/dashboard. Now, as a part of my junits, I am supposed to take the backup of the database used by this application and restore it to its earlier state as the application inserts some data across multiple tables as a part of the tests. So, I need to restore the DB before the tests run. Now, I am able to backup and restore it using java program (junit) but the problem is coming when the server is running. It says DB is already in use and can't restore. Is there a way to disconnect the db connection (user) used in the application, do the restoration and then connect back again so that I don't have to shutdown the server and start it manually again.
Using commands similar to following -
BACKUP DATABASE [Store] TO DISK = N'"+backuppath+"' WITH NOFORMAT, NOINIT,
NAME = 'demodb-full', SKIP, NOREWIND, NOUNLOAD, STATS = 10";
And
RESTORE DATABASE ["+dbName+"] FROM DISK='"+database_backup_location+"' WITH
REPLACE, MOVE '"+mdfLogicalName+"' TO
'"+getPropertyByKey("databse.dbfiles.location")+mdfLogicalName+".mdf', MOVE
'"+ldfLogicalName+"' TO
'"+getPropertyByKey("databse.dbfiles.location")+ldfLogicalName+".ldf';
Error that I am getting -
org.springframework.jdbc.UncategorizedSQLException: StatementCallback;
uncategorized SQLException for SQL [RESTORE DATABASE ....error code [3101];
Exclusive access could not be obtained because the database is in use.; nested
exception is com.microsoft.sqlserver.jdbc.SQLServerException: Exclusive access
could not be obtained because the database is in use.
I am already using the BACKUP and RESTORE commands. RESTORE command
gives error because the database is in use.
I've already answered, you just need to set your database offline this way:
alter database myDB set offline with rollback immediate
Doing this you'll disconnect all the users from your db and now you can make a RESTORE
You need to do below steps :
Backup the database
BACKUP DATABASE [Store] TO DISK = N'"+backuppath+"' WITH NOFORMAT, NOINIT,
NAME = 'demodb-full', SKIP, NOREWIND, NOUNLOAD, STATS = 10";
Kill existing connections
USE master;
DECLARE #kill varchar(8000); SET #kill = '';
SELECT #kill = #kill + 'kill ' + CONVERT(varchar(5), spid) + ';'
FROM master..sysprocesses
WHERE dbid = db_id('Store')
EXEC(#kill);
Then run the restore script.

How to grant privileges to current user

I'm trying to make a java application that uses a database. I've downloaded db2 and created a user 'student'. I have the following lines in my program:
con = DriverManager.getConnection(url, "student", "xxxxxx");
and
ResultSet rs= stmt.executeQuery("SELECT sifra, naziv " +
" FROM predmet " +
" WHERE bodovi > 20" );
And the second one throws a SqlSyntaxErrorException with the following message: DB2 SQL Error: SQLCODE=-551, SQLSTATE=42501.
So I looked it up and it seems that the user doesn't have the required level of privilege. So when I tried to run the query in db2 command line, I got:
The statement failed because the authorization ID does not have the required authorization or privilege to perform the operation. Authorization ID: "STUDENT". Operation: "SELECT".
So since obviously I barely know what I'm doing, I don't know how to grant 'student' the necessary privileges. That is, I don't know what user could give him the privileges since I never created another user. I've seen 'db2admin' mentioned (I'm using windows), but I don't know what to do with that piece of information. I don't know how to check the existing users or which password to use for db2admin (if that's even possible).
If you wish for this user to have access you need to determine at what level: Server, Instance, Database, Table, etc. Here is an article about DB2 Granting and various levels.
To make it easy, let assume this user will have full database privileges and we'll use GRANT DATABASE
GRANT ACCESSCTRL, BINDADD, CONNECT, CREATETAB, CREATE_EXTERNAL_ROUTINE,
CREATE_NOT_FENCED_ROUTINE, DATAACCESS, DATAACCESS, EXPLAIN,
IMPLICIT_SCHEMA, LOAD, QUIESCE_CONNECT, SECADM, SQLADM, WLMADM ON
DATABASE DB_STUDENT TO student;

Change the session user for DB2 while using JDBC

I have DB2 10.1 on Linux and I connect to it using Kerberos auth. Problem is that my user doesn't have permissions to do stuff so I need to impersonate another user using "SET SESSION_USER = otheruser".
This works fine if I use a client like DBArtisan, but I need to do this using JDBC and it doesn't seem to work. I've tried to execute the query every time a connection is created, I can query the value of the register and it has changed, but I still get errors if I try to query the tables my user doesn't have access to but the session user does.
Any ideas?
I have never used DB2, but a little googling led me to this page:
specialRegisters=special-register-name=special-register-value,…special-register-name=special-register-value
A list of special register settings for the JDBC connection. You can
specify one or more special register name and value pairs. Special
register name and value pairs must be delimited by commas (,). The
last pair must end with a semicolon (;). For example:
String url =
"jdbc:db2://sysmvs1.stl.ibm.com:5021/STLEC1" +
":user=dbadm;password=dbadm;" +
"specialRegisters=CURRENT_PATH=SYSIBM,CURRENT CLIENT_USERID=test" + ";";
Connection con =
java.sql.DriverManager.getConnection(url);
For special registers that can be set through IBM Data Server Driver
for JDBC and SQLJ Connection properties, if you set a special register
value in a URL string using specialRegisters, and you also set that
value in a java.util.Properties object using the following form of
getConnection, the special register is set to the value from the URL
string.
As SESSION_USER is a special register, this seems to imply you need to specify it with your connection properties as
specialRegisters=SESSION_USER=otheruser;
Either in the JDBC url, or in the properties.
However as I have never used DB2, I don't know if this is the actual solution.
Normally the server-wide database connection pools are created with a specific user with the proper permissions as decided by the DBAs. Why don't you just ask your DBAs for the appropriate grants for that user? This would be the 'kind' approach instead of trying to circumvent their permissions policies by some java piece of code, something they may not like if they know of...

Implementing a User Login, JDBC Transactions question

I have a question regarding database transactions where I'm not sure if my understanding is correct. I want to implement a user login in a java application. As there might be multiple servers acting on the same database, and each user can only log in one of those servers, the database has to store a flag if a user is already logged in.
So assume following table structure:
ID | User | PWD | Server
where Server is the reference to the server where the user is logged in to, or NULL if he's not logged in.
When a user logs in, I have to first check if the server value is NULL, and if not, set it to the correspondig reference value. But what happens when in between these 2 statements the user logs in on another server? Can such a condition be detected by transactions? e.g. (pseudo)
conn.setAutoCommit(false);
ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM users WHERE user = 'usr' AND password = 'pwd'");
if (rs.next()) {
rs.getInt("Server");
if (rs.wasNull()) {
// Not logged in
conn.createStatement().execute("UPDATE users SET server = 123 WHERE user = 'usr' AND password = 'pwd'");
conn.commit();
}
} else {
// Usr/Pwd wrong
}
conn.rollback();
What happens if the user logs in between the select and update statements on another server? does the commit fail as the table was altered by someone else during the transaction, or is it executed nontheless?
Should I better use an approach like
UPDATE users SET server = 123 WHERE user = 'usr' AND pwd = 'pwd' AND server IS NULL
and check if 0 rows were affected? If so I have to check if the user exists in a query.
Simmilar issues arise when registering a new user with INSERT. Shoud I use the transaction approach, or declare the user column as UNIQUE and catch SQL exceptions?
Using transactions as you suggest with your pseudocode will solve this, but make sure to set you transaction isolation level to TRANSACTION_REPEATABLE_READ. See this tutorial for details.
You also need to think abount:
Never, never, never store plain text passwords in the database. You need to use a one-way hash. Also, make sure to pay attention to the hashing-algorithm and implementation. Search for "HBGary" and "Anonymous" to read about what might happen if you don't.
Think about what will happen if the user logs in to one server, and the client crashes before he has a chance to log out.
In the case of updating the user's row, you can specify to lock that particular row so that no other jdbc connection can modify it.

How to count open db connections?

I'm developing a web app using Java servlet to access Mysql db, how can I get the number of connections to my DB that is currently open ?
Edit :
I tried "show processlist", it showed me : 2695159, but that's not right, I'm just developing this new project, I'm the only user, couldn't have that many processes running, what I want is the number of users accessing my project's DB, not the number of all db users, but just the ones logged in to my database which has only one table.
Depending on your MySQL version, you can perform a select on
SELECT COUNT(*) FROM information_schema.PROCESSLIST;
and you can do a where between the user, database, and host IP.
For example:
USE information_schema;
SELECT COUNT(*) FROM PROCESSLIST WHERE db ="mycase" AND HOST LIKE "192.168.11.174%"
You could use the MySQL command show processlist to get the number of connections.
However that'll also show you any connections made with the same userID to the database which may not be coming from your servlet.
In general I would suggest that you're probably better off using a Connection Pool object (see http://java-source.net/open-source/connection-pools) to manage your connections to the MySQL server. This can increase performance by making DB connections persistent, so you don't always have the overhead of a new DB connection for each page load.
If your servlet needs to know the number of connections then your Connection Pool should come with a method that tells you how many connections are currently active.
show status like 'Threads_connected'
or
show global status like 'Threads_connected'
Not sure about the difference between those two in a user-context, and you might still suffer from the problem that you would see all connections, not only those from your app.
you can even check Threads_running to only see running threads (e.g not sleeping).
Run the following query, it lists out host name and no. of connections from each host:
SELECT host,count(host) FROM information_schema.processlist GROUP BY host;
show processlist
You can only select from Information_Schema.Processlist the data that belongs to you. It means you can use it for monitoring ONLY if you're logged in as root, otherwise you will be seeing the connections coming from your user you got logged in with.
If you want proper monitoring SQL, it will be:
SELECT variable_value
FROM INFORMATION_SCHEMA.GLOBAL_STATUS
WHERE variable_name='threads_connected'
You also can count open connection by show the status from Threads_connected variable name like this:
SHOW STATUS WHERE variable_name = 'Threads_connected';
Or you can also count the process list directly from information_schema.PROCESSLIST like below:
SELECT COUNT(*) FROM information_schema.PROCESSLIST;
You may use this
SHOW GLOBAL STATUS;
or
show global status like "Threads_connected";
from Connections status you can findout total number of connections.

Categories